Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re Legacy code : format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat]

I often try to build a lot of old simulator and disk and tape archive tools, with recent GCC. Some errors are easy to fix, but I'm not so good a programmer.

I get :

itstar.c: In function ‘addfiles’:
itstar.c:194:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
itstar.c:194:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat]

from this code fragment :

/* add files to a DUMP tape */
/* output buffer must have been initialized with resetbuf() */
static void addfiles(int argc,char **argv)
{
    int c=argc;
    char **v=argv;

    while(c--) {
        addfile(argc,argv,*v++);
    }
    if(verify)
        printf("Approximately %d.%d' of tape used\n",count/bpi/12,
            (count*10/bpi/12)%10);
}

Where line 194 is the third from last, beginning with printf.

The file is itstar.c, from tapetools, code here.

It builds despite the warning, but I prefer to know how to prevent it,
so the result is more efficient and there is less chance of data corruption.

Please, what have I missed, and need to change ?

Thank you in advance.

like image 469
Kuze Avatar asked Dec 15 '13 03:12

Kuze


3 Answers

Use format specifier %lu instead of %d and your compiler should stop complaining.

printf("Approximately %lu.%lu' of tape used\n", count/bpi/12, (count*10/bpi/12)%10);
like image 133
Fiddling Bits Avatar answered Oct 11 '22 13:10

Fiddling Bits


This is undefined behavior, which means anything can happen including appearing to work correctly and then break later on down the road.

Looking at the source we can see both count and bpi are unsigned long:

extern unsigned long bpi; /* tape density in bits per inch */
extern unsigned long count; /* count of tape frames written */ 

the correct format specifier for these would be %lu.

The first argument to printf specifies a string to print out which can contain conversion specifiers beginning with % that usually specifies the types of the subsequent arguments, so in your example:

"Approximately %d.%d' of tape used\n"
               ^^ ^^
               1  2

both conversion specifiers 1 and 2 are %d which means that printf will expect the next two arguments to be of type int but they are really of type unsigned long.

If we look at the draft C99 standard section 7.19.6.1 The fprintf function which also covers printf for format specifiers, says:

If a conversion specification is invalid, the behavior is undefined.248) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

so you need to fix the format specifier which is incorrect and your warning will go away and you will be back in well defined behavior land.

like image 31
Shafik Yaghmour Avatar answered Oct 11 '22 14:10

Shafik Yaghmour


Use %lu instead of %d. %d is used for type int, %lu for unsigned long.

like image 24
tommyo Avatar answered Oct 11 '22 14:10

tommyo