简体   繁体   English

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

[英]Operator 'sizeof' with conditional (ternary) expression

I have a hard time understanding sizeof 's behaviour when given a ternary expression. 在给出三元表达式时,我很难理解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;
}

In this example (tested with gcc 4.4.3 and 4.7.2, compiled with -std=c99 ), b is 9 (8 characters + implicit '\\0' ), c is 1 (implicit '\\0' ). 在这个例子中(用gcc 4.4.3和4.7.2测试,用-std=c99编译),b是9(8个字符+隐式'\\0' ),c是1(隐式'\\0' )。 a, for some reason, is 4 . a,出于某种原因,是4

I would expect a to be either 9 or 1, based on whether argc is greater than 1. I thought maybe the string literals get converted to pointers before being passed to sizeof , causing sizeof(char*) to be 4. 根据argc是否大于1,我希望a为9或1.我想也许字符串文字在传递给sizeof之前转换为指针,导致sizeof(char*)为4。

I tried replacing STRING and "" by char arrays... 我尝试用char数组替换STRING""

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

... but I got the same results (a=4, b=9, c=1). ...但我得到了相同的结果(a = 4,b = 9,c = 1)。

Then I tried to dive into the C99 spec , but I did not find any obvious explanation in it. 然后我试着深入研究C99规范 ,但我没有找到任何明显的解释。 Out of curiosity I also tried changing changing x and y to other types: 出于好奇,我也尝试将x和y更改为其他类型:

  • char and long long int : a becomes 8 charlong long int :a变为8
  • both short or both char : a becomes 4 short或两个char :a变为4

So there's definitely some sort of conversion going on, but I struggle to find any official explanation. 所以肯定会有某种转换,但我很难找到任何官方解释。 I can sort of imagine that this would happen with arithmetic types (I'm vaguely aware there's plenty of promotions going on when those are involved), but I don't see why a string literal returned by a ternary expression would be converted to something of size 4 . 我可以想象这会发生在算术类型上(我隐约意识到当涉及这些时会有大量的促销活动),但是我不明白为什么三元表达式返回的字符串文字会被转换为某种东西4号

NB: on this machine sizeof(int) == sizeof(foo*) == 4 . 注意:在这台机器上sizeof(int) == sizeof(foo*) == 4

Follow-up 跟进

Thanks for the pointers guys. 感谢指点家伙。 Understanding how sizeof and ?: work actually led me to try a few more type mashups and see how the compiler reacted. 了解sizeof?: work实际上是如何让我尝试更多类型的mashup并看看编译器如何反应。 I'm editing them in for completeness' sake: 为了完整起见,我正在编辑它们:

foo* x = NULL; /* or foo x[] = {} */
int  y = 0;    /* or any integer type */

int a = sizeof(argc > 1 ? x : y);

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

With foo x[], bar y[] , foo* x, bar* y or foo* x, bar y[] , the warning becomes pointer type mismatch . 使用foo x[], bar y[]foo* x, bar* yfoo* x, bar y[] ,警告变为pointer type mismatch No warning when using a void* . 使用void*时没有警告。

float x = 0; /* or any floating-point type */
int   y = 0; /* or any integer type */

int a = sizeof(argc > 1 ? x : y);

Yields no warning, and a == sizeof(x) (that is, the floating-point type). 不产生警告,并且a == sizeof(x) (即浮点类型)。

float x = 0;    /* or any floating-point type */
foo*  y = NULL; /* or foo y[] = {} */

int a = sizeof(argc > 1 ? x : y);

Yields error: type mismatch in conditional expression . 收益率error: type mismatch in conditional expression

If I ever read the spec completely I'll make sure to edit this question to point to the relevant parts. 如果我完全阅读了规范,我将确保编辑此问题以指向相关部分。

You have to understand expressions , which are the core component of the language. 您必须了解表达式 ,这是该语言的核心组件。

Every expression has a type . 每个表达式都有一个类型 For an expression e , sizeof e is the size of the type of the value of the expression e . 对于表达式esizeof e是表达式e的值的类型的大小。

The expression a ? b : c 表达a ? b : c a ? b : c has a type. a ? b : c有一种类型。 The type is the common type of the two operand expressions b and c . 类型是两个操作数表达式bc通用类型

In your example, the common type of char[9] and char[1] is char * (both array-valued expressions decay to a pointer to the first element). 在您的示例中, char[9]char[1]的常见类型是char * (两个数组值表达式都衰减为指向第一个元素的指针)。 (In C++, the rules for string literals are different and there is a const everywhere.) (在C ++中,字符串文字的规则是不同的,并且到处都有一个const 。)

You need to understand that sizeof is entirely a compile-time operator. 您需要了解sizeof完全是编译 sizeof算符。 With VLA it could return a variable expression, otherwise it is a compile-time constant. 使用VLA,它可以返回变量表达式,否则它是一个编译时常量。

What matters is the type of its argument. 重要的是它的论点类型。

So in sizeof(argc > 1 ? STRING : "") the condition is not evaluated. 所以在sizeof(argc > 1 ? STRING : "")评估条件。 The type of the argument is decayed to const char* . 参数的类型被衰减为const char* And on your machine, it is 4. 在你的机器上,它是4。

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

Since STRING is macro-expanded to the "a string" literal, sizeof(STRING) is 9, nearly as if you have declared 由于STRING被宏扩展为"a string"字面值,因此sizeof(STRING)为9,几乎就像你声明的那样

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

Both STRING and "" are array objects of types char[9] and char[1] respectively. STRING""分别是char[9]char[1]类型的数组对象。 In C language, when array objects are used in expressions, they get implicitly converted (decay) to pointer types in almost all contexts, with few well-known specific exceptions. 在C语言中,当在表达式中使用数组对象时,它们几乎在所有上下文中都被隐式转换(衰减)为指针类型,几乎没有众所周知的特定异常。

One of such exceptions is sizeof operator. 其中一个例外是sizeof运算符。 When you use an array object as an immediate operand of sizeof that array object does not decay to pointer type, and you get the size of the entire array in bytes as result. 当您使用数组对象作为sizeof的立即操作数时,该数组对象不会衰减为指针类型,并且您将获得整个数组的大小(以字节为单位)。 This is why sizeof(STRING) is equivalent to sizeof(char[9]) and evaluates to 9 . 这就是sizeof(STRING)等于sizeof(char[9])并计算为9 And sizeof("") is equivalent to sizeof(char[1]) and evaluates to 1 . sizeof("")相当于sizeof(char[1])并且计算结果为1

But when you use array objects as operands of ?: operator, the context is no longer exceptional. 但是当您使用数组对象作为?:运算符的操作数时,上下文不再是例外。 In context of ?: operator arrays immediately decay to pointers. ?:运算符数组的上下文中,会立即衰减为指针。 This means that your sizeof(argc > 1 ? STRING : "") is equivalent to sizeof(argc > 1 ? (char *) STRING : (char *) "") , and in turn equivalent to sizeof(char *) . 这意味着你的sizeof(argc > 1 ? STRING : "")相当于sizeof(argc > 1 ? (char *) STRING : (char *) "") ,并且相当于sizeof(char *) This evaluates to pointer size on your platform, which just happens to be 4 . 这将评估您平台上的指针大小,恰好是4

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

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