具有条件(三元)表达式的运算符’sizeof’

当给出三元表达式时,我很难理解sizeof的行为。

 #define STRING "a string" int main(int argc, char** argv) { int a = sizeof(argc > 1 ? STRING : ""); int b = sizeof(STRING); int c = sizeof(""); printf("%d\n" "%d\n" "%d\n", a, b, c); return 0; } 

在这个例子中(用gcc 4.4.3和4.7.2测试,用-std=c99编译),b是9(8个字符+隐式'\0' ),c是1(隐式'\0' )。 a,出于某种原因,是4

根据argc是否大于1,我希望a为9或1.我想也许字符串文字在传递给sizeof之前转换为指针,导致sizeof(char*)为4。

我尝试用char数组替换STRING""

 char x[] = ""; char y[] = "a string"; int a = sizeof(argc > 1 ? x : y); 

…但我得到了相同的结果(a = 4,b = 9,c = 1)。

然后我试着深入研究C99规范 ,但我没有找到任何明显的解释。 出于好奇,我也尝试将x和y更改为其他类型:

  • charlong long int :a变为8
  • short或两个char :a变为4

所以肯定会有某种转换,但我很难找到任何官方解释。 我可以想象这会发生在算术类型中(我隐约意识到当涉及到这些时会有大量的促销活动),但是我不明白为什么三元表达式返回的字符串文字会被转换为某种东西4号

注意:在这台机器上sizeof(int) == sizeof(foo*) == 4

跟进

感谢指点家伙。 了解sizeof?: work实际上是如何让我尝试更多类型的mashup并看看编译器如何反应。 为了完整起见,我正在编辑它们:

 foo* x = NULL; /* or foo x[] = {} */ int y = 0; /* or any integer type */ int a = sizeof(argc > 1 ? x : y); 

产生warning: pointer/integer type mismatch in conditional expression [enabled by default] ,以及a == sizeof(foo*)

使用foo x[], bar y[]foo* x, bar* yfoo* x, bar y[] ,警告变为pointer type mismatch 。 使用void*时没有警告。

 float x = 0; /* or any floating-point type */ int y = 0; /* or any integer type */ int a = sizeof(argc > 1 ? x : y); 

不产生警告,并且a == sizeof(x) (即浮点类型)。

 float x = 0; /* or any floating-point type */ foo* y = NULL; /* or foo y[] = {} */ int a = sizeof(argc > 1 ? x : y); 

收益率error: type mismatch in conditional expression

如果我完全阅读了规范,我将确保编辑此问题以指向相关部分。

你必须理解表达式 ,它是语言的核心组成部分。

每个表达式都有一个类型 。 对于表达式esizeof e是表达式e的值的类型的大小。

表达式a ? b : c a ? b : c有一个类型。 类型是两个操作数表达式bc通用类型

在您的示例中, char[9]char[1]的常见类型是char * (两个数组值表达式都衰减为指向第一个元素的指针)。 (在C ++中,字符串文字的规则是不同的,并且到处都有一个const 。)

您需要了解sizeof完全是编译 sizeof算符。 使用VLA,它可以返回变量表达式,否则它是一个编译时常量。

重要的是其论点的类型。

所以在sizeof(argc > 1 ? STRING : "")评估条件。 参数的类型被衰减为const char* 。 在你的机器上,它是4。

您应该编写代码(argc > 1)?sizeof(STRING):1

由于STRING被宏扩展为"a string"文字,因此sizeof(STRING)为9,几乎就像你声明的那样

 const char STRING[] = {'a',' ','s','t','r','i','n','g','\0'}; 

STRING""分别是char[9]char[1]类型的数组对象。 在C语言中,当在表达式中使用数组对象时,它们几乎在所有上下文中都被隐式转换(衰减)为指针类型,几乎没有众所周知的特定exception。

其中一个例外是sizeof运算符。 当您使用数组对象作为sizeof的立即操作数时,该数组对象不会衰减为指针类型,并且您将获得整个数组的大小(以字节为单位)。 这就是sizeof(STRING)等于sizeof(char[9])并计算结果为9 。 而sizeof("")相当于sizeof(char[1])并且计算结果为1

但是当您使用数组对象作为?:运算符的操作数时,上下文不再是例外。 在?:运算符数组的上下文中,会立即衰减为指针。 这意味着你的sizeof(argc > 1 ? STRING : "")相当于sizeof(argc > 1 ? (char *) STRING : (char *) "") ,并且相当于sizeof(char *) 。 这将评估您平台上的指针大小,恰好是4