请参阅我的代码:
#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;
}
我发现<stdint.h>
中的宏定义是:
#define INT8_C(val) ((int8_t) + (val))
此加号的含义或含义是什么?
答案 0 :(得分:27)
摘录:
((int8_t) + (78));
是一个表达式,它取值78
,应用一元+
,然后将其转换为int8_t
类型,然后将其丢弃。这与法律表达没有什么不同:
42;
a + 1;
还评估表达式然后丢弃结果(尽管如果编译器可以判断出没有副作用,这些可能会被优化掉)。
这些“裸”表达式在C语言中完全有效,通常只有当它们有副作用时才有用,例如i++
计算i
,并将其抛出,副作用是它递增值。
你应该使用该宏的方式更像是:
int8_t varname = INT8_C (somevalue);
标准中可以找到看似冗余的一元+
运算符的原因。引用C99 6.5.3.3 Unary arithmetic operators /1
:
一元+或 - 运算符的操作数应具有算术类型;
而且,在6.2.5 Types, /18
:
整数和浮点类型统称为算术类型。
换句话说,一元+
阻止您使用宏中的所有其他数据类型,例如指针,复数或结构。
最后,你的原因是:
signed char + 78;
代码段不起作用是因为它不是一回事。这个开始声明一个signed char
类型的变量,但是当它到达+
时会窒息,因为那不是合法的变量名。要使其等效于您的工作代码段,您可以使用:
(signed char) + 78;
将值+78
转换为signed char
类型。
而且,根据C99 7.8.14 Macros for integer constants /2
,您还应该注意在这些宏中使用非常量,但它们不能保证工作:
这些宏的任何实例中的参数都应该是一个非整数常量(如 在6.4.4.1)中定义,其值不超过相应类型的限制。
6.4.4.1
只是指定各种后缀(U
,UL
,ULL
,L
的各种整数格式(十进制/八进制/十六进制), LL
和小写的等价物,具体取决于类型)。底线是它们必须是常量而不是变量。
例如,glibc
有:
# 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
这将允许您的INT8_C
宏正常工作,但文本INT64_C(val)
会预先处理为valL
或valLL
,这两者都不是您想要的。
答案 1 :(得分:18)
似乎每个人都错过了这里的一元加运算符,这是为了使结果在#if
预处理程序指令中有效。给出:
#define INT8_C(val) ((int8_t) + (val))
指令:
#define FOO 1
#if FOO == INT8_C(1)
展开为:
#if 1 == ((0) + (1))
因此按预期工作。这是因为#define
指令中的任何非#if
d符号都会扩展为0
。
如果没有一元加号(在#if
指令中成为二进制加),则表达式在#if
指令中无效。
答案 2 :(得分:10)
这是一个一元+
运算符。它产生其操作数的值,但它只能应用于算术类型。这里的目的是防止在指针类型的表达式上使用INT8_C
。
但你的陈述表达
INT8_C(val);
有未定义的行为。 INT8_C()
的参数必须是“一个不固定的整数常量......其值不超过相应类型的限制”(N1256 7.18.4)。这些宏的目的是让您编写类似INT64_C(42)
的内容,如果42L
为int64_t
,则将其展开为long
,如果42LL
则展开为int64_t
1}}很长,等等。
但要写
((int8_t) + (78));
或
((int8_t) + (val));
在您自己的代码中是完全合法的。
修改强>:
问题中INT8_C()
的定义:
#define INT8_C(val) ((int8_t) + (val))
在C99中有效,但根据后来的N1256草案,由于其中一项技术勘误更改而不符合。
最初的C99标准,第7.18.4.1p2节,说:
宏 INT *** N * _C **( value )应扩展为有符号整数常量 指定的值和类型 int_least *** N * _t **。
N1256将其更改为(第3段):
其中一个宏的每次调用都应扩展为整数 常量表达式适用于 #if 预处理指令。 表达式的类型应与a的类型相同 根据表达式转换的相应类型 整数促销。表达式的值应该是 参数。
此更改是针对Defect Report #209进行的。
EDIT2 :但是看看R ..的答案;它实际上在N1256中有效,原因相当模糊。
答案 3 :(得分:0)
这是一个加号。
只能做可以做的事情。
它将所谓的通常的算术转换应用于操作数。这为结果建立了通用实际类型。如果要将结果投入特定的事情,我想不出有任何理由强迫这样做。
它将操作数限制为定义了算术运算符的类型。这似乎是更可能的原因。