I am wondering why do we cast constants when using #define
preprocessor?
For example:
#define WIDTH 128
Would it be equal to -128
in an 8bit platform?
What if I change it like this:
#define WIDTH 128U
What would it be equal to, on 8bit platform?
What is the default sizeof a constant integers like the above? Do its length/type depends on the platform architecture, or it depends on the type of the literal value they hold?
Sorry about my bad English.
Defining WIDTH
as 128
poses no problems, int
is at least 16 bit wide on all conforming platforms.
Defining WIDTH
as 128U
would make it an unsigned integer constant literal. Since the value fits in an unsigned int
(mandated to be at least 16 bit wide), it has type unsigned int
. sizeof(WIDTH)
evaluates to sizeof(unsigned int)
, which is entirely platform specific.
Using this suffix is not recommended . It would have surprising side effects:
if (WIDTH > -1) {
printf("This will never print\n");
}
Since WIDTH
expands to 128U
, an unsigned
constant, the comparison is performed as an unsigned comparison, -1
is converted to unsigned
and becomes UINT_MAX
, a value much larger than 128
. Don't do this.
If you subsequently store WIDTH
into a char
variable, you may have a problem. It would actually not make a difference whether you define it as 128
or 128U
, you would still have an overflow if the char
type is 8 bit and signed, leading to undefined behavior. On most platforms, the value stored would indeed be -128
but you cannot even rely on that.
More importantly, you should use all the help the compiler can give you by enabling all compiler warnings and making them errors:
gcc -Wall -Wextra -Werror
or
clang -Weverything -Werror
Very few of these warnings are annoying, most of them are very useful and point to silly mistakes, typos and oversights.
First of all 128
is not equal to -128
on a 8-bit platform.
Second this has nothing to do with the preprocessor. What the preprocessor does is to replace WIDTH
with whatever it's defined as. That is the question is why you write 128
or 128u
in your source.
The suffix u
is not about type casting, it's about to indicate the type of the literal. In this example 128
is an literal with value 128 of type int
while 128u
is a literal with value 128 of type unsigned int
. It's not a problem immediately here, but if you start to use them and end up larger than 32767
you could run into problems. For example:
#define WIDTH 256u
#define HEIGHT 192u
unsigned npixels = WIDTH * HEIGHT;
it should be noted that the suffices are required to make it portable (what could happen is that the platform only uses 16-bit int
s and with int the multiplication would overflow which means undefined behavior).
Also note that in newer C standards (but not the antique ones) will extend the literal to become as large as necessary if possible. For example the literal 32768
means a signed integral type with value 32768
, if int
isn't large enough to hold that signed number then larger types would be used.
The sizeof
these integers are the same as sizeof(int)
as the type of the literals are int
and unsigned int
. The actual value of sizeof(int)
could be any positive integer.
Giving C99 chapters because I don't have the C11 document at hand.
ISO/IEC 9899:1999, 6.4.4.1 Integer constants
The type of an integer constant is the first of the corresponding list in which its value can be represented.
For decimal constants without suffix:
int
long int
long long int
For decimal constants with u
or U
suffix:
unsigned int
unsigned long int
unsigned long long int
ISO/IEC 9899:1999, 5.2.4.2.1 Sizes of integer types
The width of integer types is implementation-defined, as is the binary representation.
INT_MAX
-- the largest value an int
can take -- is guaranteed to be at least +32767
.
UINT_MAX
-- the largest value an unsigned int
can take -- is guaranteed to be at least 65535
.
ISO/IEC 9899:1999, 6.3.1.8 Usual arithmetic conversions
If you compare an int
with an unsigned int
, the int
will be implicitly converted to unsigned int
for the comparison. Similar for the short
/ long
/ long long
types. As @chqrlie pointed out, this can be a problem; your compiler should give you a warning if this happens (you are always compiling with -Wall -Wextra
/ /W3
enabled, aren't you?).
Summary
Your constants will fit into an int
/ unsigned int
even on an 8-bit machine. Assuming they would not, the compiler would use the next largest type for them (instead of casting the value).
As for why we do it...
If you, for example, intend to use WIDTH
for comparisons with the result of sizeof()
, or the return code of strlen()
, or anything else that is unsigned
by nature, you would want WIDTH
to have the same value domain, ie being able to hold all possible values.
That is why you would want WIDTH
to be unsigned
as well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.