caramel1995
caramel1995

Reputation: 3055

C int datatype and its variations

Greetings , and again today when i was experimenting on language C in C99 standard , i came across a problem which i cannot comprehend and need expert's help.

The Code:

    #include <stdio.h>

    int main(void)
   {
    int Fnum = 256; /* The First number to be printed out */

    printf("The number %d in long long specifier is %lld\n" , Fnum , Fnum);

    return 0;
   }

The Question:

1.)This code prompted me an warning message when i try to run this code.

2.)But the strange thing is , when I try to change the specifier %lld to %hd or %ld, the warning message were not shown during execution and the value printed out on the console is the correct digit 256 , everything also seems to be normal even if i try with %u , %hu and also %lu.In short the warning message and the wrong printing of digit only happen when I use the variation of long long specifier.

3.)Why is this happening??I thought the memory size for long long is large enough to hold the value 256 , but why it cannot be used to print out the appropriate value??

The Warning Message :(For the above source code)

C:\Users\Sam\Documents\Pelles C Projects\Test1\Test.c(7): warning #2234: Argument 3 to 'printf' does not match the format string; expected 'long long int' but found 'int'.

Thanks for spending time reading my question.God bless.

Upvotes: 1

Views: 653

Answers (4)

zwol
zwol

Reputation: 140866

There are three things going on here.

  1. printf takes a variable number of arguments. That means the compiler doesn't know what type the arguments (beyond the format string) are supposed to be. So it can't convert them to an appropriate type.
  2. For historical reasons, however, integer types smaller than int are "promoted" to int when passed in a variable argument list.
  3. You appear to be using Windows. On Windows, int and long are the same size, even when pointers are 64 bits wide (this is a willful violation of C89 on Microsoft's part - they actually forced the standard to be changed in C99 to make it "okay").

The upshot of all this is: The compiler is not allowed to convert your int to a long long just because you used %lld in the argument list. (It is allowed to warn you that you forgot the cast, because warnings are outside standard behavior.) With %lld, therefore, your program doesn't work. But if you use any other size specifier, printf winds up looking for an argument the same size as int and it works.

Upvotes: 3

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272792

This is due to the way varargs work in C. Unlike a normal function, printf() can take any number of arguments. It is up to the programmer to tell printf() what to expect by providing a correct format string.

Internally, printf() uses the format specifiers to access the raw memory that corresponds to the input arguments. If you specify %lld, it will try to access a 64-bit chunk of memory (on Windows) and interpret what it finds as a long long int. However, you've only provided a 32-bit argument, so the result would be undefined (it will combine your 32-bit int with whatever random garbage happens to appear next on the stack).

Upvotes: 1

Neil
Neil

Reputation: 55432

When dealing with a variadic function, the caller and callee need some way of agreeing the types of the variable arguments. In the case of printf, this is done via the format string. GCC is clever enough to read the format string itself and work out whether printf will interpret the arguments in the same way as they have been actually provided.

You can get away with slightly different types of arguments in some cases. For example, if you pass a short then it gets implicitly converted to an int. And when sizeof(int) == sizeof(long int) then there is also no distinction. But sizeof(int) != sizeof(long long int) so the parameter fails to match the format string in that case.

Upvotes: 1

yan
yan

Reputation: 20992

You're passing the Fnum variable to printf, which is typed int, but it's expecting long long. This has very little to do with whether a long long can hold 256, just that the variable you chose is typed int.

If you just want to print 256, you can get a constant that's typed to unsigned long long as follows:

printf("The number %d in long long specifier is %lld\n" ,256 , 256ULL);

or cast:

printf("The number %d in long long specifier is %lld\n" , Fnum , (long long int)Fnum);

Upvotes: 6

Related Questions