-5

The code below gives the output without error in Turbo C compiler, and gives the address of variable and its value both:

int a=5,*fp;
fp=&a;
printf("%d %d\n",fp,*fp);

But when I compile the same code in Linux with GCC compiler, it gives an error:

`warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d %d\n",fp,*fp);`

But the same code with the %p format specifier works in GCC Compiler ,to which I agree. The question is: how come it's working on Turbo C platform?

P.S. The issue is not that (in Turbo C) the error is not reported but it's that on Turbo C it gives a signed integer value that is unchanged on repeated execution of the program; can it be garbage?

P.P.S Turbo C is running on MSDOS platform and GCC on 64-bit Linux, if that helps.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
FossArduino
  • 161
  • 2
  • 2
  • 11
  • Undefined behavior does not necessarily cause your compiler to report an error or warning. But that doesn't mean that your code is any less broken. – Bill Lynch May 13 '15 at 03:39
  • Gcc does not issue an error. It issues a *warning*, which is not the same thing at all. That it is able to recognize and diagnose a *bona fide* problem when Turbo C does not is a matter of quality of implementation. – John Bollinger May 13 '15 at 03:40
  • What does "the code actually prints the value of memory location" mean? Show some output examples if you say this is about the output. – viraptor May 13 '15 at 03:43
  • it gave a signed integer value and the value didn't change even as i repeatedly executed the program which means its not garbage? – FossArduino May 13 '15 at 03:48
  • I have updated my code please check sorry – FossArduino May 13 '15 at 03:56
  • GCC is correct to issue that warning, since you are trying to print a pointer as if it was an `int`. Even though this should work in most cases, an `int` and a pointer don't necessarily have the same size, and this is relevant to the well behaviour of `printf()`. – Havenard May 13 '15 at 03:58
  • you are correct i think if we combine your and isanae's answer we get the complete answer – FossArduino May 13 '15 at 03:59
  • 1
    `printf("%d",fp,*fp);` is not "same code" as `printf("%d %d\n",fp,*fp);` – M.M May 13 '15 at 04:01
  • "gives a signed integer value that is unchanged on repeated execution of the program hence I inferred that its not garbage" - the value of your pointers cannot be expected to stay the same, unless you know this is the case on your platform. If you're asking, you shouldn't assume it. – viraptor May 13 '15 at 04:05
  • `whether MSDOS is 32 or 64 bit`: MS-DOS never made it past 16-bit. – isanae May 13 '15 at 04:05
  • @MattMcNabb well spotted - this may have been the output difference he's talking about! – viraptor May 13 '15 at 04:06
  • maybe its just garbage value but how to check? i think isanae has got a point – FossArduino May 13 '15 at 04:11

4 Answers4

2

printf() assumes you will pass a signed int for the %d specifier.

On the platform and compiler you are using, ints and pointers are probably the same size and printf() is able to display it correctly. Your pointer is reinterpreted as an int.

Compiling and running this on a different platform where, for example, ints are 32-bit and pointers are 64-bit (such as gcc on x64) would be undefined behaviour. If you are lucky enough, it would crash. If not, you'd get garbage.

isanae
  • 3,253
  • 1
  • 22
  • 47
1

The %d conversion specifier requires the corresponding argument to have type [signed] int. If the corresponding argument in fact has a different type then the behavior is explicitly undefined. This is the case regardless of the relative sizes of the expected and actual types, and regardless of whether implicit or explicit conversion between those types is possible.

Neither the behavior of the compiler nor that of any part of any resulting compiled program is defined when the program exhibits undefined behavior. Turbo C is not required to diagnose the problem. On the other hand, gcc is quite permitted to diagnose it, and even to reject the source code with an error instead of merely alerting you with a warning. As far as C is concerned, the whole program's behavior can be absolutely anything if any undefined behavior is triggered -- from what the author intended (whatever that may be) to emitting rude comments from the machine's speaker, and far beyond.

In practice, the undefined behavior is likely (but by no means certain) to manifest in a relatively benign way if the expected and actual types are the same size, and the conversion specifier is not %s. Otherwise, all bets are off. Note in particular that many C implementations for 64-bit platforms feature 32-bit ints and 64-bit pointers.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • "The whole program being undefined" only happens when it is guaranteed that execution would reach the line triggering UB – M.M May 13 '15 at 04:16
  • 1
    @MattMcNabb, I have updated my answer to clarify that the part about whole program behavior applies in the event that undefined behavior is actually triggered. I think that's technically accurate, though the distinction between that and UB being *guaranteed* to be triggered is largely one of (English language) semantics, especially given that programs cannot predict the future. – John Bollinger May 13 '15 at 04:24
1

Each conversion specifier, such as %d, specifies both the type of the required argument and the format used to print it.

  • %d requires an argument of type int (equivalently signed int), and prints it in decimal.
  • %u requires an argument of type unsigned int and prints it in decimal.
  • %x requires an argument of type unsigned int and prints it in hexadecimal.

And so forth.

In your code:

int a=5,*fp;
fp=&a;
printf("%d %d\n",fp,*fp);

the second %d is correct, since the corresponding argument, *fp is of type int. But the first is incorrect, since the corresponding argument fp is of type int*.

If you pass an argument of the wrong type for a conversion specifier, the behavior is undefined. A compiler is not required to warn you if you do this, since it's not possible to detect the error in the most general case (the format string doesn't have to be a string literal). Some compilers, including gcc, will analyze format strings if they're string literals and warn about mismatches. Turbo C apparently does not (that's not surprising, it's a very old compiler).

The correct format for printing a pointer value is %p. This requires an argument of type void*, and prints it in an implementation-defined manner. A pointer of a type other than void* should be converted.

The correct version of your code is:

int a = 5, *fp;
fp = &a;
printf("%p %d\n", (void*)fp, *fp);
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

It's a warning, not an error. The first compiler could also say the same, but doesn't.

The warning doesn't stop the compilation, so it will work too. They're just different compilers. Also, compiler accepting your program doesn't mean that the program is correct.

viraptor
  • 33,322
  • 10
  • 107
  • 191
  • The warning does not stop compilation, but whether the resulting program "works" in any reasonable sense of the term is literally undefined. It is quite likely to produce behavior different from the expected if built and run as a 64-bit application on a system with 32-bit `int`s and 64-bit pointers, which are very common today. – John Bollinger May 13 '15 at 03:45