Search code examples
cprintfwarningsbit-fieldsgcc-warning

Are there better ways to ease this warning?


I have a struct where I use bitfields to optimize memory. I have a uint64_t type and I want to print its value. When compiled it shows me this warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 5 has type ‘long unsigned int:48’ [-Wformat=]

I have already tried to supress this warning by typing while compiling -Wno-format. I'm wondering if there are a better way to do it.

Here some code:

#include <stdint.h>
#include <stdio.h>

typedef struct gn_addr 
{
    unsigned int m:1;
    unsigned int st:5;
    unsigned int reserved:10;
    uint64_t mid:48;
} gn_addr ;

void gn_addr__print(gn_addr *self)                                                                                                                                                                         
{                                                                                                                                                                                                          
    printf("M=>%d\nST=>%d\nReserved=>%d\nMID=>%lu\nTotal size %ld bytes\n",                                                                                                                                
         self->m, self->st, self->reserved, self->mid, sizeof(self));                                                                                                                                   
} 

Solution

  • While you should definitely apply the fixes in the other answers to get portable format specifiers, the warning will persist. The reason is that extra arguments to a variadic function like printf undergo argument promotions. Argument promotions include integer promotion.

    The rules for integer promotions will convert any integer with a conversion rank less than int/unsigned, as well as bit-fields, into the an int/unsigned. So for your initial bit-fields, you get int automatically.

    For integers with a higher conversion rank than int/unsigned, no promotion occurs. So your bit-field is not promoted to an uint64_t, and you get a warning about argument mismatch. You need a cast.

    (uint64_t)self->mid
    

    Btw, since nobody mentioned, the portable format specifier for a size_t (the type of the sizeof operator) is %zu. You should use that instead of %ld.