简体   繁体   English

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

[英]What is this mysterious macro plus sign in stdint.h?

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: 我发现<stdint.h>中的宏定义是:

#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. 是一个表达式,取值78 ,应用一元+ ,然后将其转换为int8_t类型,然后将其丢弃。 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. 这些“裸”表达式在C中完全有效,并且通常仅在它们具有副作用时才有用,例如i++ ,它计算i并将其抛出,副作用是增加值。

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 : 引用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 : 并且,在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. 这个开始声明一个类型为signed char的变量,但是当它到达+时会发出chokes,因为那不是合法的变量名。 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 . 这是输入值+78以键入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: 并且,根据C99 7.8.14 Macros for integer constants /2 ,您还应该小心在这些宏中使用非常量,它们不能保证工作:

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中所定义),其值不超过相应类型的限制。

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). 6.4.4.1简单地指定各种后缀( UULULLLLL和小写等价物,具体取决于类型)的各种整数格式(十进制/八进制/十六进制)。 The bottom line is that they have to be constants rather than variables. 底线是它们必须是常数而不是变量。

For example, glibc has: 例如, 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

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. 这将允许您的INT8_C宏正常工作,但文本INT64_C(val)将被预处理为valLvalLL ,这两者都不是您想要的。

Seems everyone has missed the point of the unary plus operator here, which is to make the result valid in #if preprocessor directives. 似乎每个人都错过了这里的一元加运算符,这是为了使结果在#if预处理器指令中有效。 Given: 鉴于:

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

the directives: 指令:

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

expand as: 扩展为:

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

and thus work as expected. 因此按预期工作。 This is due to the fact that any un #define d symbol in an #if directive expands to 0 . 这是因为#if指令中的任何un #define d符号都扩展为0

Without the unary plus (which becomes a binary plus in #if directives), the expression would not be valid in #if directives. 如果没有一元加号(在#if指令中成为二进制加),表达式在#if指令中无效。

It's a unary + operator. 这是一个一元+操作员。 It yields the value of its operand, but it can be applied only to arithmetic types. 它产生其操作数的值,但它只能应用于算术类型。 The purpose here is to prevent the use of INT8_C on an expression of pointer type. 这里的目的是防止在指针类型的表达式上使用INT8_C

But your statement expression 但你的陈述表达

INT8_C(val);

has undefined behavior. 有未定义的行为。 The argument to INT8_C() is required to be "an unsuffixed integer constant ... with a value that does not exceed the limits for the corresponding type" ( N1256 7.18.4). INT8_C()的参数必须是“一个不固定的整数常量......其值不超过相应类型的限制”( N1256 7.18.4)。 The intent of these macros is to let you write something like INT64_C(42) and have it expand to 42L if int64_t is long , or to 42LL if int64_t is `long long, and so forth. 这些宏的目的是让你写类似INT64_C(42)并把它扩大到42L如果int64_tlong ,或者42LL如果int64_t是`很长很长,等等。

But writing either 但是要么写作

((int8_t) + (78));

or 要么

((int8_t) + (val));

in your own code is perfectly legal. 在你自己的代码中是完全合法的。

EDIT : 编辑

The definition for INT8_C() in the question: 问题中INT8_C()的定义:

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

is valid in C99, but is non-conforming according to the later N1256 draft, as a result of a change in one of the Technical Corrigenda. 在C99中有效,但根据后来的N1256草案,由于其中一项技术勘误更改,因此不符合要求。

The original C99 standard, section 7.18.4.1p2, says: 最初的C99标准,第7.18.4.1p2节,说:

The macro INT***N* _C**( value ) shall expand to a signed integer constant with the specified value and type int_least***N* _t**. INT *** N * _C **( )应扩展为带有指定值的有符号整数常量,并输入int_least *** N * _t **。

N1256 changed this to (paragraph 3): N1256改为(第3段):

Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. 其中一个宏的每次调用都应扩展为适合在#if预处理指令中使用的整数常量表达式。 The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. 表达式的类型应与根据整数提升转换的相应类型的表达式具有相同的类型。 The value of the expression shall be that of the argument. 表达式的值应该是参数的值。

The change was made in response to Defect Report #209 . 该变更是针对缺陷报告#209进行的

EDIT2 : But see R..'s answer; EDIT2 :但是看看R ..的回答; it's actually valid in N1256, for quite obscure reasons. 由于非常模糊的原因,它在N1256中实际上是有效的。

That's a unary plus. 这是一个加号。

There are only two things it could be doing. 它只能做两件事。

  1. It applies what are know as the usual arithmetic conversions to the operand. 它将通常的算术转换应用于操作数。 This establishes a common real type for a result. 这为结果建立了一个共同的实际类型 I can't think of any reason to force this if the result is about to be cast into something specific. 如果要将结果转化为特定的东西,我想不出任何理由强迫这一点。

  2. It restricts the operand to types for which arithmetic operators are defined. 它将操作数限制为定义了算术运算符的类型。 This seems like the more likely reason. 这似乎是更可能的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM