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

发布于 2024-12-08 06:46:38 字数 430 浏览 3 评论 0原文

请看我的代码:

#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;
}

我发现中的宏定义是:

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

这个加号的含义或意义是什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烟花肆意 2024-12-15 06:46:38

代码片段:

((int8_t) + (78));

是一个表达式,它采用值78,应用一元+,然后将其转换为int8_t< /code> 输入,然后扔掉它。它与合法表达式没有真正的区别:

42;
a + 1;

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

这些“裸”表达式在 C 中完全有效,并且通常仅当它们具有副作用时才有用,例如使用 i++,它会计算 i 并将其与副作用一起丢弃因为它增加了价值。

应该使用该宏的方式更像是:

int8_t varname = INT8_C (somevalue);

看似多余的一元+运算符的原因可以在标准中找到。引用 C99 6.5.3.3 一元算术运算符 /1

一元+或-运算符的操作数应为算术类型;

并且,在 6.2.5 类型,/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 只是指定各种整数格式(十进制/八进制/十六进制)以及各种后缀(UULULLLLL 以及小写等效项,具体取决于类型)。最重要的是它们必须是常量而不是变量。

例如,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,这两者都是您不想要的。

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.

三生路 2024-12-15 06:46:38

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

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

指令:

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

扩展为:

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

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

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

Seems everyone has missed the point of the unary plus operator here, which is to make the result valid in #if preprocessor directives. 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#defined symbol in an #if directive expands to 0.

Without the unary plus (which becomes a binary plus in #if directives), the expression would not be valid in #if directives.

橪书 2024-12-15 06:46:38

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

但是你的语句表达式

INT8_C(val);

有未定义的行为。 INT8_C() 的参数必须是“一个无后缀的整型常量...其值不超过相应类型的限制”(N1256 7.18.4)。这些宏的目的是让您编写类似 INT64_C(42) 的内容,并在 int64_tlong 时将其扩展为 42L,或者如果 int64_t 是 `long long,则为 42LL,依此类推。

但是在您自己的代码中编写

((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 中有效,原因很不明朗。

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.

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

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:

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

The original C99 standard, section 7.18.4.1p2, says:

The macro INT***N*_C**(value) shall expand to a signed integer constant with
the specified value and type int_least***N*_t**.

N1256 changed this to (paragraph 3):

Each invocation of one of these macros shall expand to an integer
constant expression suitable for use in #if preprocessing directives.
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.

EDIT2: But see R..'s answer; it's actually valid in N1256, for quite obscure reasons.

横笛休吹塞上声 2024-12-15 06:46:38

这是一元加号。

它只能做两件事。

  1. 它将所谓的常见算术转换应用于操作数。这为结果建立了一个公共实数类型。如果结果即将转换为特定的内容,我想不出有任何理由强制执行此操作。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文