获取可变长度数组的 sizeof——这样做有什么好处吗?

问题描述 投票:0回答:2

我正在处理一段遗留代码(没有测试)。我偶然发现了一个隐藏在几个宏中的部分。如果使用 GCC 的

-Wvla
.

编译,它会生成警告

问题代码相当于这个小程序中可以看到的内容:

typedef struct entry {
    unsigned index;
    unsigned reserved;
    unsigned value;
} entry_t;

int main(int argc, char **argv) {
    long pa = 0;
    long res = pa + sizeof(entry_t[10 - argc]);
    return res;
}

编译时,它给出警告:

$ gcc -g -Wvla repro-vla.c
repro-vla.c: In function ‘main’:
repro-vla.c:9:5: warning: ISO C90 forbids variable length array [-Wvla]
    9 |     long res = pa + sizeof(entry_t[10 - argc]);
      |     ^~~~

罪魁祸首当然是这个表情:

sizeof(entry_t[10 - argc])
。这里的语法有点混乱。我相信为
10 - argc
类型的
entry_t
条目创建了一个临时匿名数组,然后采用它的大小,并丢弃数组。

我的问题是:

  1. 我对现在编写的代码的理解是否正确?
  2. 这个表达方式与
    sizeof(entry_t) * (10-argc)
    有什么不同?两者都计算相同的值,并且都没有采取任何措施来防止下溢(当
    argc >= 10
    时)。第二个表达式不使用可变长度数组,因此不会生成警告,而且在我看来也更容易理解。
arrays c sizeof c89 variable-length-array
2个回答
0
投票

在此表达式中

sizeof(entry_t[10 - argc])
两个数组都没有创建。计算了表达式
10 - argc
,并根据
entry_t
的类型计算了这样一个数组的大小。
entry_t[10 - argc]
是类型说明符而不是表达式。所以例如你可能不会写

sizeof entry_t[10 - argc]

这些表达式

sizeof(entry_t[10 - argc])
sizeof(entry_t) * (10-argc)
产生相同的值,因为数组的大小等于数组中元素的数量乘以其元素的大小。

相对于 VLA 数组中的元素数量,C 标准中有一个限制,即 “每次评估时,它的值都应大于零。”

注意在这个表达式

sizeof(entry_t) * (10-argc)
中,当
size_t
由于通常的算术转换而大于
argc
时,您可以获得类型
10
的非常大的值。

还有这条线

long res = pa + sizeof(entry_t[10 - argc]);

产生一个问题,为什么无符号整数类型

size_t
的值赋值给有符号整数类型
long
的变量。


0
投票

采用可变长度数组的 sizeof——这样做有什么好处吗?

我没有看到任何好处。我看到了替代代码的好处。

sizeof(entry_t) * (10-argc)
argc >= 10 时有一个定义的乘积
*1
sizeof(entry_t[10 - argc])
undefined behavior (UB) 在这种情况下,因为它不满足“如果大小是一个表达式,它不是一个整数常量表达式:......每次评估它都应该有一个大于零的值” C17dr § 6.7.6.2 5(数组声明符)

接下来的代码步骤,转换为

long
,然后转换为
int
,当
sizeof(entry_t) * (10-argc)
大于
LONG_MAX, INT_MAX
时,它们的实现定义了行为。


*1 确定键入

size_t
.

© www.soinside.com 2019 - 2024. All rights reserved.