Reputation: 2676
I was trying this code.
#include <stdio.h>
#include <stdlib.h>
#define LOWER 0
#define UPPER 300
int main()
{
printf("%d %f",LOWER,UPPER);
return 0;
}
I read some of the answers and it says that defined constants don't have a type and are not allocated any memory. Then why is it giving errors if i specify different type specifiers in printf()?
Upvotes: 7
Views: 9749
Reputation: 66254
In your example, both are pushed into the variadic parameter list of printf as int values. This can cause problems with the format flags in the format string of printf()
do not match the underlying type. Refer to this post for reasons why undefined behavior can ensue.
As hideous as it seems, one way to know you can get what you're looking for in this printf
is to do this:
#include <stdio.h>
#include <stdlib.h>
#define LOWER 0
#define UPPER 300
int main()
{
printf("%d %f", (int)LOWER, (float)UPPER);
return 0;
}
In both cases, these are preprocessor macros that are substituted before compilation. Note that if UPPER cannot be promoted to a float
you will receive a compiler error, which is a good thing. if it can be, it will be, and the printf()
will find the bytes it needs to print what it wants. The same is true for int
and LOWER respectively. The above printf will degenerate to this after preprocessing:
printf("%d %f", (int)0, (float)300);
Now imagine your macros were instead declared as such:
#define LOWER 100.0
#define UPPER 300.0
The original printf()
will present as thus after preprocessing:
printf("%d %f", 100.0, 300.0);
which may seem right, but is that 100.0 float really going to be properly excised by the %d
format string handler in printf()
? Make sure. Doing what we did before:
printf("%d %f", (int)LOWER, (float)UPPER);
now preprocesses to:
printf("%d %f", (int)100.0, (float)300.0);
You may get a compiler warning on the float-to-int cast, you may not. Unless you want to roll the dice that what you're passing is sized to what is byte-size-expected by things like printf()
you need to be damn-sure everything matches. This can get especially frustrating when the format specifier expects one thing, something different is passed in, and yet it appears to all work fine, but only on some platforms mysteriously:
printf("%ld\n", UPPER);
This may "work", but if it does it is only because a long int
and a int
are the same size on your platform. Move this code to a platform where long int
and int
are different bit-widths and its UB all the way.
Bottom line: If you're passing preprocessor macros into variadic parameter lists for things like printf()
that have size expectations for the data being pushed (as specified by the format string for example) you better make sure what you're pushing is what is expected.
Upvotes: 4
Reputation: 2335
#define
is a preprocessor directive. After compilation it does not exist. Instead the corresponding values will be replaced in the code. In this case actual code that is being compiled after macro expansion is
//header stdio.h
//header stdlib.h
int main()
{
printf("%d %f",0,300);
return 0;
}
And yes in this case both 0,300 are integers. !
Upvotes: 1
Reputation: 183978
In this case, the type is the type of the literal constants. Both 0
and 300
are integer constants that fit in an int
, so their type is int
.
Upvotes: 3
Reputation: 104718
It's untyped; Just look at it as a textual substitution of your source:
printf("%d %f", 0, 300);
Upvotes: 1