C99 VLA 大小确定和 sizeof 运算符

fra*_*ian 5 c language-lawyer

我写了以下内容作为关于的问题的答案的一部分sizeof,以及它在 C99 VLA 方面的行为:

有意创建一个案例,其中count_ofVLA的语义实际上不同,但创建一个可读、易于理解/可维护且有用的案例可能很困难(我还没有尝试过)。

仔细想想,我不确定这种说法是否属实。首先要创建 VLA,编译器必须首先确定 VLA 需要的空间量。

对于sizeof,我们知道

如果操作数的类型是变长数组类型,则对操作数求值;否则,不计算操作数并且结果是整数常量。(6.5.3.4/2)

尽管 VLA 大小显然是运行时确定的,但在对 VLA 声明符的大小表达式进行评估(如果有,包括任何副作用)之后:

可变长度数组类型的每个实例的大小在其生命周期内不会改变。如果大小表达式是 sizeof 运算符的操作数的一部分,并且更改大小表达式的值不会影响运算符的结果,则未指定是否计算大小表达式。(6.7.5.2/2)

所以,给定

#define count_of(arr)  (sizeof(arr)/sizeof(arr[0]))
Run Code Online (Sandbox Code Playgroud)

是否有任何其中一个宏这样的,因为这实际有效的行为可以为一个VLA与数组声明,其中阵列尺寸表达为常量表达式(即,普通老式预C99固定大小的数组)不同情况?

小智 5

显而易见的答案是何时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;
}
Run Code Online (Sandbox Code Playgroud)

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