【问题标题】:Array declared with negative buffer works if done with a variable如果使用变量完成,则使用负缓冲区声明的数组有效
【发布时间】:2026-01-25 19:00:01
【问题描述】:

我是 C 编程新手,我很难理解为什么会这样

#include <stdio.h>


int main() {
    int l = -5;
    char arr[l];

    printf("content: %s; sizeof: %d\n", arr, sizeof(arr));
}

带输出:

content: ; sizeof: -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];
      |          ^~~

我预计第一个示例也会出现错误,但我真的不知道这里发生了什么。

【问题讨论】:

  • sizeof(即size_t)结果的格式说明符是%zu。这将解开这里的一个谜。
  • 哦,我明白了,谢谢。顺便说一句,它看起来像一个巨大的数字,但问题还没有解决
  • 我认为 lchar arr[l] 转换为 size_t 这是一个无符号类型。要打印 sizeof,您需要 %zu 从 printf 获得正确的输出
  • @bolov 我只是想知道为什么文字 -5 也没有被转换。可能是因为它是一个定义而不是一个陈述。
  • 啊,可能是因为-5 不是 文字,而是带有一元- 运算符和文字5 的表达式

标签: arrays c


【解决方案1】:

这两个版本的程序都不符合 C 语言规范(即使在格式说明符被更正以正确匹配 size_t 参数之后)。但是这两种情况在语义上是不同的,它们违反了语言规范的不同规定。

先拿这个:

    char arr[-5];

表达式-5 是一个整数常量表达式,所以这是一个普通数组(不是变长数组)的声明。它受 C17 语言规范第 6.7.6.2/1 段的约束,其中部分内容是:

除了可选的类型限定符和关键字static[] 可以分隔表达式或*。如果他们分隔一个表达式 (指定数组的大小),表达式应具有 整数类型。 如果表达式是一个常量表达式,它应该 具有大于零的值

(已添加重点。)

这是语言约束的一部分,这意味着编译器有义务在观察到违规时发出诊断消息。原则上,实现不需要拒绝包含违反约束的代码,但如果他们接受这样的代码,那么语言不会定义结果。

另一方面,考虑

    int l = -5;
    char arr[l];

因为l 不是一个常量表达式(即使l 被声明为const 也不会是),上面讨论的规定不适用,另外,arr 是一个可变长度数组.这受规范第 6.7.6.2/5 段的约束,相关部分对尺寸表达式的要求是:

每次对其进行评估时,它的值都应大于零

该程序违反了该规定,但它是语义规则,而不是语言约束,因此编译器没有义务对其进行诊断,更不用说拒绝代码了。在一般情况下,编译器无法识别或诊断违反此特定规则的情况,但原则上,它可以在此特定情况下这样做。如果它接受代码,则运行时行为未定义。

为什么当您在特定硬件上使用特定 C 实现编译和运行该程序时发出 -5 不是由 C 建立的。它可能由您的实现指定,也可能不是。程序的微小变化或 C 实现的不同版本可能会产生不同的结果。

总的来说,这是 C 拒绝牵你的手的又一个例子。新的编码人员以及那些习惯于解释语言和虚拟机的人似乎经常期望系统的某些组件会在他们编写了错误的代码时通知他们。有时确实如此,但有时它只是用那些可能与程序员的想法相似或可能不相似的糟糕代码做一些事情。用 C 语言进行有效的编程需要注意细节。

【讨论】:

  • “C 拒绝牵你手的另一个例子。” --> 是的,随机用户,欢迎在没有training wheels 的情况下进行编码。
  • 非常感谢您的解释,真的很有帮助!还要感谢关于 C 的“人生课程”,我知道这会很困难,而且我知道几年前我从 Python 开始就做错了。