我是 C 语言编程的新手,我很难理解为什么这行得通
#include <stdio.h>
int main() {
int l = -5;
char arr[l];
printf("content: %s; sizeof: %d\n", arr, sizeof(arr));
}
输出:
内容:;大小:-5
这不是:
#include <stdio.h>
int main() {
char arr[-5];
printf("content: %s; sizeof: %d\n", arr, sizeof(arr));
}
输出:
name.c:6:10: error: size of array ‘arr’ is negative
6 | char arr[-5];
| ^~~
我预计第一个示例也会出现错误,但我真的不知道这里发生了什么。
最佳答案
这两个版本的程序都不符合 C 语言规范(即使在更正格式说明符以正确匹配 size_t
参数之后)。但这两种情况在语义上是不同的,它们违反了语言规范的不同规定。
先看这个:
char arr[-5];
表达式-5
是一个整数常量表达式,所以这是一个普通数组(不是变长数组)的声明。它受 C17 语言规范第 6.7.6.2/1 段的约束,其中部分内容为:
In addition to optional type qualifiers and the keyword
static
, the[
and]
may delimit an expression or*
. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero.
(强调已添加。)
这是语言约束的一部分,这意味着编译器有义务在发现违规时发出诊断消息。原则上,实现不需要拒绝包含违反约束的代码,但如果它们接受此类代码,则语言不会定义结果。
另一方面,考虑
int l = -5;
char arr[l];
因为 l
不是常量表达式(即使 l
被声明为 const
也不会是),上面讨论的规定不apply,并且,arr
是一个变长数组。这受规范第 6.7.6.2/5 段的约束,相关部分要求大小表达式:
each time it is evaluated it shall have a value greater than zero
该程序违反了该规定,但它是语义规则,而不是语言约束,因此编译器没有义务对其进行诊断,更不用说拒绝代码了。在一般情况下,编译器无法识别或诊断违反此特定规则的行为,但原则上,它可以在这种特定情况下这样做。如果它接受代码,则运行时行为未定义。
当您使用特定的 C 实现在您的特定硬件上编译和运行该程序时,为什么该程序会发出 -5
不是由 C 确定的。它可能由您的实现指定,也可能不是。程序中的微小变化或 C 实现的不同版本可能会产生不同的结果。
总的来说,这又是一个C拒绝牵你手的例子。新的编码人员以及那些习惯于解释型语言和虚拟机的编码人员似乎经常期望系统的某些组件会在他们编写错误代码时通知他们。有时它确实如此,但有时它只是用那些可能与程序员的想法相似或不相似的错误代码做一些事情。有效的 C 语言编程需要关注细节。
关于arrays - 如果用变量完成,则用负缓冲区声明的数组有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70159478/