How to set (in most elegant way) exactly n least significant bits of uint32_t? That is to write a function void setbits(uint32_t *x, int n);<         
        
If n is zero then no bits should be set based on the question.
const uint32_t masks[32] = {0x1, 0x3, 0x7, ..., 0xFFFFFFFF};
void setbits(uint32_t *x, int n)
{
    if ( (n > 0) && (n <= 32) )
    {
        *x |= masks[--n];
    }
}
                                                                        The function with a simple test:
#include <stdio.h>
#include <stdint.h>
void setbits(uint32_t *x, int n)
{
  *x |= 0xFFFFFFFF >> (32 - n);
}
int main()
{
  for (int n = 1; n <= 32; ++n)
  {
    uint32_t x = 0;
    setbits(&x, n);
    printf("%2d: 0x%08X\n", n, x);
  }
  getchar();
  return 0;
}
                                                                        Goals:
void setbits(uint32_t *x, unsigned n) {
    // As @underscore_d notes in the comments, this line is
    // produces Undefined Behavior for values of n greater than
    // 31(?). I'm ok with that, but if you're code needs to be
    // 100% defined or you're using some niche, little-used
    // compiler (perhaps for a microprocesser?), you should
    // use `if` statements. In fact, this code was just an
    // an experiment to see if we could do this in only 32-bits
    // and without any `if`s. 
    *x |= (uint32_t(1) << n) - 1;
    // For any n >= 32, set all bits. n must be unsigned
    *x |= -uint32_t(n>=32);
}
Note: if you need n to be of type int, add this to the end:
    // For any n<=0, clear all bits
    *x &= -uint32_t(n>0);
Explanation:
    *x |= -uint32_t(n>=32);
When n>=32 is true, x will be bitwise-ORed with 0xFFFFFFFF, yielding an x with all bits set.
    *x &= -uint32_t(n>0);
This line states that as long as any bit should be set, n>0, bitwise-AND x with 0xFFFFFFFF which will result in no change to x. If n<=0, x will be bitwise-ANDed with 0 and consequently result in a value of 0.
Sample program to show the algorithm works:
#include <stdio.h>
#include <stdint.h>
void print_hex(int32_t n) {
  uint32_t x = (uint32_t(1) << n);
  printf("%3d:  %08x  |%08x  |%08x  &%08x\n",
         n, x, x - 1,
         -uint32_t(n>=32),
         -uint32_t(n>0));
}
void print_header() {
  //        1:  00000002  |00000001  |00000000  &ffffffff
  printf("  n:   1 << n    (1<<n)-1   n >= 32     n <= 0\n");
}
void print_line() {
  printf("---------------------------------------------\n");
}
int main() {
  print_header();
  print_line();
  for (int i=-2; i<35; i++) {
    print_hex(i);
    if (i == 0 || i == 31) {
      print_line();
    }
  }
  return 0;
}
Output (broken up and annotated):
For n < = 0, the last step ANDs with 0 ensuring the result is 0.
  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
 -2:  40000000  |3fffffff  |00000000  &00000000
 -1:  80000000  |7fffffff  |00000000  &00000000
  0:  00000001  |00000000  |00000000  &00000000
For 1 <= n <= 31, the last two steps "OR 0, AND 0xffffffff" result in no change to the number. The only step that matters is the "OR (1<
  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
  1:  00000002  |00000001  |00000000  &ffffffff
  2:  00000004  |00000003  |00000000  &ffffffff
  3:  00000008  |00000007  |00000000  &ffffffff
  4:  00000010  |0000000f  |00000000  &ffffffff
  5:  00000020  |0000001f  |00000000  &ffffffff
  6:  00000040  |0000003f  |00000000  &ffffffff
  7:  00000080  |0000007f  |00000000  &ffffffff
  8:  00000100  |000000ff  |00000000  &ffffffff
  9:  00000200  |000001ff  |00000000  &ffffffff
 10:  00000400  |000003ff  |00000000  &ffffffff
 11:  00000800  |000007ff  |00000000  &ffffffff
 12:  00001000  |00000fff  |00000000  &ffffffff
 13:  00002000  |00001fff  |00000000  &ffffffff
 14:  00004000  |00003fff  |00000000  &ffffffff
 15:  00008000  |00007fff  |00000000  &ffffffff
 16:  00010000  |0000ffff  |00000000  &ffffffff
 17:  00020000  |0001ffff  |00000000  &ffffffff
 18:  00040000  |0003ffff  |00000000  &ffffffff
 19:  00080000  |0007ffff  |00000000  &ffffffff
 20:  00100000  |000fffff  |00000000  &ffffffff
 21:  00200000  |001fffff  |00000000  &ffffffff
 22:  00400000  |003fffff  |00000000  &ffffffff
 23:  00800000  |007fffff  |00000000  &ffffffff
 24:  01000000  |00ffffff  |00000000  &ffffffff
 25:  02000000  |01ffffff  |00000000  &ffffffff
 26:  04000000  |03ffffff  |00000000  &ffffffff
 27:  08000000  |07ffffff  |00000000  &ffffffff
 28:  10000000  |0fffffff  |00000000  &ffffffff
 29:  20000000  |1fffffff  |00000000  &ffffffff
 30:  40000000  |3fffffff  |00000000  &ffffffff
 31:  80000000  |7fffffff  |00000000  &ffffffff
For n >= 32, all bits should be set and the "OR ffffffff" step accomplishes that regardless of what the previous step may have done. The n <= 0 step is then a noop as well with AND ffffffff.
  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
 32:  00000001  |00000000  |ffffffff  &ffffffff
 33:  00000002  |00000001  |ffffffff  &ffffffff
 34:  00000004  |00000003  |ffffffff  &ffffffff