#include <stdio.h>
#define a (1,2,3)
#define b {1,2,3}
int main()
{
unsigned int c = a;
unsigned int d = b;
printf("%d\n",c);
printf("%d\n",d);
return 0;
}
以上C代码会将输出打印为3
和1
。
但是#define a (1,2,3)
和#define b {1,2,3}
在没有构建警告的情况下如何取a = 3和b = 1,以及()
和{}
如何给出不同的值?>
答案 0 :(得分:8)
请记住,预处理器只是替换宏。因此,根据您的情况,您的代码将被转换为此:
#include <stdio.h>
int main()
{
unsigned int c = (1,2,3);
unsigned int d = {1,2,3};
printf("%d\n",c);
printf("%d\n",d);
return 0;
}
在第一种情况下,您从,
运算符获得结果,因此c
等于3
。但是在第二种情况下,您将获得d
的初始值设定项列表的第一个成员,因此您将获得1
作为结果。
如果您将代码编译为c++
,则第二行会产生错误。但似乎您可以在c
中编译此代码。
答案 1 :(得分:4)
除了其他答案,
unsigned int d = {1,2,3};
(在宏替换之后)
在C语言中无效。它违反了6.7.9 Initialization:
初始化器不得尝试为未包含在正在初始化的实体中的对象提供值。
使用更严格的编译选项(gcc -std=c17 -Wall -Wextra -pedantic test.c
),gcc会产生:
warning: excess elements in scalar initializer
unsigned int d = {1,2,3};
^
但是请注意
unsigned int d = {1};
有效,因为允许initializing scalar with braces。只是前一片段存在问题的额外初始化器值。
答案 2 :(得分:1)
对于c
,初始化器是一个表达式,其值为3。对于d
,初始化器是一个用大括号括起来的列表,并且它提供了太多的值,其中只有第一个是使用。
宏扩展后,c
和d
的定义为:
unsigned int c = (1,2,3);
unsigned int d = {1,2,3};
在C语法中,出现在unsigned int c =
或unsigned int d =
之后的初始化器可以是 assignment-expression 或{{1} } initializer-list {
(并且该列表中可能有最后一个逗号)。 (来自C 2018 6.7.9 1。)
第一行中的}
是 assignment-expression 。特别是,它是(1,2,3)
expression (
形式的 primary-expression 。也就是说, expression 使用逗号运算符;它的格式为 expression )
assignment-expression 。我将省略语法的继续扩展。可以说,
是用逗号运算符构建的表达式,而逗号运算符的值只是其右手操作数。因此1,2,3
的值为2,1,2
的值为3。括号表达式的值是其内部表达式的值,因此1,2,3
的值为3.因此,(1,2,3)
被初始化为3。
相反,在第二行中,c
是{1,2,3}
initializer-list {
。根据C子句6.7.9中的文字, initializer-list 提供用于初始化所定义对象的值。 }
…{
形式用于初始化数组和结构,但也可用于初始化标量对象。如果我们写了}
,这会将unsigned int d = {1};
初始化为1。
但是,6.7.9 2是一个约束条件,上面写着:“初始化程序不得尝试为未包含在正在初始化的实体中的对象提供值。”这意味着您提供的初始值可能不会超过要提供的值。初始化。因此,d
违反了约束。需要编译器才能生成诊断消息。另外,您的编译器似乎继续运行,仅使用列表中的第一个值来初始化unsigned int d = {1,2,3};
。其他的都是多余的,被忽略了。
(另外,6.7.9 11说“标量的初始化程序应该是单个表达式,可以选择用大括号括起来。”)