stdint.h中这个神秘的宏加号是什么?

时间:2011-10-04 02:05:28

标签: c macros stdint

请参阅我的代码:

#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))

此加号的含义或含义是什么?

4 个答案:

答案 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只是指定各种后缀(UULULLL的各种整数格式(十进制/八进制/十六进制), 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)会预先处理为valLvalLL,这两者都不是您想要的。

答案 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)的内容,如果42Lint64_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)

这是一个加号。

只能做可以做的事情。

  1. 它将所谓的通常的算术转换应用于操作数。这为结果建立了通用实际类型。如果要将结果投入特定的事情,我想不出有任何理由强迫这样做。

  2. 它将操作数限制为定义了算术运算符的类型。这似乎是更可能的原因。