6

I am new to linux. I use gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 on Ubuntu 12.04 LTS. When I compiled the c program using pointer, I got the -Wformat warning as shown below. But if I execute a.out file, I get the correct result. Can anyone please tell me why I got the message and suggest me what I should do to overcome?.

My testing program:

 #include<stdio.h>

void main(void)

{

int x=10,y,z;
int *p=&x ;

        printf("\n\np  = %u\n",p);
        printf("\n*p = %u\n",*p);
        printf("\n&x = %u\n",&x);
        printf("\n&y = %u\n",&y);
        printf("\n&z = %u\n",&z);
        printf("\n&p = %u\n\n",&p);
}

Output:

qust1-Array.c:11:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:14:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:15:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:16:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:17:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat]
9
  • 4
    This is off topic as it's a general programming in C question, but int * and unsigned int are not the same thing.
    – dobey
    Apr 1, 2013 at 13:33
  • @dobey Programming in Ubuntu in on-topic per the FAQ.
    – Seth
    Apr 1, 2013 at 14:05
  • 3
    @Seth Very basic core concepts of programming languages is not part of that.
    – dobey
    Apr 1, 2013 at 16:42
  • 2
    @Seth Programming that it is some way specifically related to Ubuntu is on-topic here, including situations where something worked one way on one platform and another way on Ubuntu. Questions about how to use development tools are on-topic too. I often answer questions of both types. But there's no consensus that all programming questions that happen to somehow involve Ubuntu are on-topic, and it's hard to see a good reason for us to expand the scope of our site to cover such a big percentage of Stack Overflow's scope. IMO the best thing to do here is to migrate this to Stack Overflow. Apr 1, 2013 at 20:29
  • 2
    Similarly, if someone plays a game on Ubuntu and has trouble starting it up, we help them even if they could have the same problem on another platform. If they have trouble killing Big Boss Wizard Monster Guy, that's only on-topic here if the problem is that a technique that works on another platform doesn't work here. Once a question is no longer platform-specific, not geared to Ubuntu-specific development, and about the art of programming rather than how to use a tool, I don't see why we need to consider it on-topic. (We also don't teach people English grammar to use in LibreOffice.) Apr 1, 2013 at 20:31

1 Answer 1

5

You are getting the warnings because you are using the wrong format specifier in printf(). p is an integer-pointer. &p is the address of a pointer. &x and &y are addresses of integers. These are all addresses in memory, not values of a variable. The specifier %u is for values of unsigned integers. So you are printing apples where the compiler expects oranges. Addresses are shorter than some values stored in variables. By using %u will actually print an address value as decimal (highly unusual) and some more data located behind that in memory. The compiler is complaining, because that's probably not what you want to do. To print the addresses use the specifier %p, as in:

printf("\n&x = %p\n",&x);

Aside from that, your variables are signed integers and as such should use %i instead of %u. The %u format specifier of printf() is for positive integers only. For small positive values both, %i and %u are interchangeable. The warning is displayed because the variable type does not match its specifier and this causes problems in some cases.

This would be more sensible from your variable types:

printf("\n\np  = %p\n",  p); // p is a pointer so %p would print the address

printf("\n*p = %i\n",   *p); // the data saved at that address is an integer 
                             // so %i is appropriate if you dereference the 
                             // pointer with the star "*p"

printf("\n&x = %p\n",   &x); // &x gives the address of the integer variable x 
                             // so %p is the specifier for that address

printf("\n&y = %p\n",   &y);
printf("\n&z = %p\n",   &z);

printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is 
                             // stored -> still an address -> %p is the right
                             // specifier

A bit background on signed and unsigned integers and pointers:

C uses the same 32 bit (or another power of two depending on the system architecture) to store unsigned and signed integers. Thus the highest unsigned int is 232-1 or in binary notation:

232-1 = (11111111111111111111111111111111)2 <- (unsigned)

And a the number one would look like this in binary:

       1 = (00000000000000000000000000000001)2 <- (unsigned)

Now regular signed integers need to store the negative numbers as well, but still in the same space of 32 bit. If you stored the sign, of the number in e.g. the first bit, you would loose a whole bit. That would be wasteful, e.g. the zero would have two representations as + and - zero. To circumvent this problem negative numbers in signed integers are stored a little differently: To encode a number into a signed integer, you add halve the possible range for your 32 bit number. This is 2(32-1), and then use the regular binary representation of that new number. So a one is encoded like 2(32-1) + 1 would be for an unsigned integer. We have:

 2(32-1) = (11111111111111111111111111111111)2 <-signed

         ...

         1 = (10000000000000000000000000000001)2 <- signed

         0 = (10000000000000000000000000000000)2 <- signed

        -1 = (01111111111111111111111111111111)2 <- signed

         ...

-2(32-1) = (00000000000000000000000000000000)2 <-signed

Now you have encoded the same number of integers, but the maximum for signed integers is consequently only 2(32-1) as opposed to double that, 232-1, for unsigned integers. This is called excess-K or offset-binary representation for negative numbers. Most systems use the Two's complement, where the first, most significant bit is reversed.

To see this, set x=-1; and then printf("%u",x). You will get the following output:

2147483648

Which is 232-1 or (01111111111111111111111111111111)2 in binary notation. For the Two's complement this number would be:

4294967295

Or 232-1. This equals (11111111111111111111111111111111)2 in binary, so it has the first bit reversed compared to the above excess-K value of 2147483648.

So this is how the data is stored. Pointers come into play when you think of the where. The physical bits in the memory must have addresses. Since there are incredibly many of them you address them in chunks of more then one bit. If you create a pointer, the physical memory at the address of the pointer holds another address in memory. So a house is a physical object, much like a bit in your PC's memory. A piece of paper would be a pointer. It is smaller than the house, but can hold the address of a house or other houses. In that analogy, above you would have tried to demolish the piece of paper instead of the actual house and it was actually a mountain...

2
  • 2
    A lengthy explanation, but wrong. The actual issue is that the format specifier is for an unsigned int, but the arguments are pointers (or arrays, or pointers to pointers, if you prefer).
    – dobey
    Apr 1, 2013 at 16:47
  • And of course you are right, dobey. I did not scroll to the end of the warning. Nonetheless one should use %i for signed integers.
    – con-f-use
    Apr 1, 2013 at 17:11

Not the answer you're looking for? Browse other questions tagged .