When I executed the code of this question, I got this warning:
warning: format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
printf("P-Q: %d, P: %d, Q: %d", (p - q), p, q);
~^ ~~~~~~~
%ld
As a reflex fix, I used %ld
to print the subtraction of two pointers. And the compiler agreed.
Fortunately, I saw a comment from another user mentioning that %td
should be used, since the result type of the subtraction is ptrdiff_t
. This answer confirms this claim.
Now from GCC's header file of stddef.h, I can see that these types are equivalent in this case:
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#define __PTRDIFF_TYPE__ long int
However, I was just going to suggest a wrong (more or less) fix to the OP, with %ld
, instead of %td
.
Is there a way I could have understood that the compiler warning alone was not enough? Or maybe to wisely have interpreted the warning itself, and not just react.
Compiler warnings are messages produced by a compiler regarding program code fragments to be considered by the developer, as they may contain errors. Unlike compilation errors, warnings don't interrupt the compilation process.
TreatWarningsAsErrors. The TreatWarningsAsErrors option treats all warnings as errors. You can also use the TreatWarningsAsErrors to set only some warnings as errors. If you turn on TreatWarningsAsErrors, you can use WarningsNotAsErrors to list warnings that shouldn't be treated as errors.
The warning message for each controllable warning includes the option that controls the warning. That option can then be used with -Werror= and -Wno-error= as described above. (Printing of the option in the warning message can be disabled using the -fno-diagnostics-show-option flag.)
I don't think you can tell. It depends on the intent/caution/smartness of the compiler writer.
Maybe he decided he would always support %ld
where %td
is expected, or maybe he was just unaware/unable/unwilling to give a more detailed/proper message. In case of doubt, your last resort is the standard.
This doesn't seem to be a portable construct and for "orthodoxy" you should support both format specifiers.
The key here is: don't do any form of arithmetic inside printf
in the first place. Separate algorithm from GUI.
Code such as printf("%d", p - q)
is very dangerous, not just because you might get the types wrong logically, but also since C might "do you a favour" and silently change the types through implicit type promotion. Examples.
In addition, most compilers don't warn for wrong format specifiers. This is a relatively new thing in the history of C, since compilers aren't required to show a diagnostic message here. It is just a bonus feature of gcc.
How to avoid bugs? These functions are inherently dangerous - that's just how it is and everyone knows it. Probably printf & scanf family of functions are the most harmful functions ever written in the history of programming, in terms of total bug cost caused to mankind. So what you should do to:
stdio.h
if possible and keep it away from production-quality code. Portability is not always more important than robust code - sometimes it is preferable to use the raw console API. Avoid variable argument list functions in general.stdio.h
inside a separate file, which you should be doing anyway. Don't mix printing/input with algorithms. Make an interface which is using pointers.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With