19

请看我的代码:

#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

4 回答 4

26

片段:

((int8_t) + (78));

是一个表达式,它接受 value 78,应用 unary +,然后将其转换为int8_t类型,然后将其丢弃。它与法律表达没有真正的不同:

42;
a + 1;

它还评估表达式然后丢弃结果(尽管如果编译器可以判断没有副作用,这些可能会被优化不存在)。

这些“裸”表达式在 C 中完全有效,并且通常仅在它们具有副作用时才有用,例如 with 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转换为 type signed char

而且,根据 C99 7.8.14 Macros for integer constants /2,您还应该小心在这些宏中使用非常数,它们不能保证工作:

这些宏的任何实例中的参数应该是一个无后缀的整数常量(如 6.4.4.1 中定义的),其值不超过相应类型的限制。

6.4.4.1只需指定各种整数格式(十进制/八进制/十六进制) ,并带有各种后缀(UULULL、和小写等效项,具体取决于类型)。底线是它们必须是常量而不是变量。LLL

例如,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)将被预处理为valLor valLL,您都不需要。

于 2011-10-04T02:09:22.070 回答
17

似乎每个人都错过了这里一元加号运算符的要点,即使结果在#if预处理器指令中有效。鉴于:

#define INT8_C(val) ((int8_t) + (val))

指令:

#define FOO 1
#if FOO == INT8_C(1)

展开为:

#if 1 == ((0) + (1))

从而按预期工作。这是因为指令#define中的任何 und 符号都#if扩展为0.

如果没有一元加号(在指令中变为二元加号#if),则表达式在指令中将无效#if

于 2011-10-04T05:12:16.843 回答
10

它是一元运算+符。它产生其操作数的值,但它只能应用于算术类型。这里的目的是防止使用INT8_C指针类型的表达式。

但是你的语句表达

INT8_C(val);

具有未定义的行为。to 的参数INT8_C()必须是“一个无后缀的整数常量……其值不超过相应类型的限制”(N1256 7.18.4)。这些宏的目的是让您编写类似的东西INT64_C(42)并将其扩展为42Lif int64_tislong42LLif int64_tis `long long 等等。

但是写要么

((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预处理指令中使用的整数常量表达式。表达式的类型应与根据整数提升转换的相应类型的表达式具有相同的类型。表达式的值应该是参数的值。

更改是针对缺陷报告 #209进行的。

EDIT2:但请参阅 R.. 的回答;由于非常模糊的原因,它实际上在 N1256 中有效。

于 2011-10-04T02:11:19.900 回答
0

这是一个单一的加号。

它只能做两件事。

  1. 它将通常的算术转换应用于操作数。这为结果建立了一个共同的实型。如果结果即将被转换成特定的东西,我想不出任何理由来强制这样做。

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

于 2011-10-04T02:23:04.157 回答