Please see my code:
#include <stdint.h>
int main(int argc, char *argv[])
{
unsigned char s = 0xffU;
char ch = 0xff;
int val = 78;
((int8_t) + (78)); /*what does this mean*/
INT8_C(val); /*equivalent to above*/
signed char + 78; /*not allowed*/
return 0;
}
I find that the macro definition in <stdint.h>
is:
#define INT8_C(val) ((int8_t) + (val))
What is the meaning or significance of this plus sign?
The snippet:
((int8_t) + (78));
is an expression, one that takes the value 78
, applies the unary +
, then casts that to an int8_t
type, before throwing it away. It is no real different to the legal expressions:
42;
a + 1;
which also evaluate the expressions then throw away the result (though these will possibly be optimised out of existence if the compiler can tell that there are no side effects).
These "naked" expressions are perfectly valid in C and generally useful only when they have side effects, such as with i++
, which calculates i
and throws it away with the side effect being that it increments the value.
The way you should be using that macro is more along the lines of:
int8_t varname = INT8_C (somevalue);
The reason for the seemingly redundant unary +
operator can be found in the standard. Quoting C99 6.5.3.3 Unary arithmetic operators /1
:
The operand of the unary + or - operator shall have arithmetic type;
And, in 6.2.5 Types, /18
:
Integer and floating types are collectively called arithmetic types.
In other words, the unary +
prevents you from using all the other data types in the macro, such as pointers, complex numbers or structures.
And, finally, the reason your:
signed char + 78;
snippet doesn't work is because it's not the same thing. This one is starting to declare a variable of type signed char
but chokes when it gets to the +
since that's not a legal variable name. To make it equivalent to your working snippet, you would use:
(signed char) + 78;
which is the casting of the value +78
to type signed char
.
And, as per C99 7.8.14 Macros for integer constants /2
, you should also be careful with using non-constants in those macros, they're not guaranteed to work:
The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.
6.4.4.1
simply specifies the various integer formats (decimal/octal/hex) with the various suffixes (U
, UL
, ULL
, L
, LL
and the lower-case equivalents, depending on the type). The bottom line is that they have to be constants rather than variables.
For example, glibc
has:
# define INT8_C(c) c
# define INT16_C(c) c
# define INT32_C(c) c
# if __WORDSIZE == 64
# define INT64_C(c) c ## L
# else
# define INT64_C(c) c ## LL
# endif
which will allow your INT8_C
macro to work fine but the text INT64_C(val)
would be pre-processed into either valL
or valLL
, neither of which you would want.