C99 VLA 大小确定和 sizeof 运算符

C99 VLA size determination and sizeof operator

作为对 关于 sizeof 及其在 C99 VLA 方面的行为的回答的一部分,我写了以下内容:

It would not be difficult to intentionally create a case where the semantics of count_of would effectively differ for a VLA but it might be difficult to create a readable, easily understandable/maintainable, and useful case (I haven't tried to).

想了想,我不确定这个说法是否属实。首先要创建 VLA,编译器必须首先确定 VLA 需要的 space 数量。

对于sizeof,我们知道

If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant. (6.5.3.4/2)

虽然 VLA 大小显然是 运行 时间确定,但在对 VLA 声明符的大小表达式求值(如果有的话,包括任何副作用)之后:

The size of each instance of a variable length array type does not change during its lifetime. Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. (6.7.5.2/2)

所以,给定

#define count_of(arr)  (sizeof(arr)/sizeof(arr[0]))

是否存在任何情况,其中宏的实际有效行为对于 VLA 与数组大小表达式为常量表达式的数组声明可能不同(即一个普通的 C99 之前的固定大小数组)?

显而易见的答案是 arr 是一个包含副作用的表达式。如果计算 sizeof 的参数,就会产生副作用。如果不评估,则没有副作用。

#include <stdio.h>
#define LENGTHOF(arr) (sizeof(arr) / sizeof(*(arr)))
void f() {
  puts("f");
}
int main() {
  const int n = 4;
  int array[n];
  return LENGTHOF(*(f(), &array)) - 4;
}

这在 C99 中有效,其中 array 是 VLA,而在 C++ 中,n 是常量表达式,而 array 不是 VLA。在 C99 中,这会打印 f。在 C++ 中,这不会打印任何内容。