C - 初始化器不是字符串字面量常量

7

我知道在c语言中,文件作用域的初始化器有一些限制:你不能使用变量(即使是const),函数等等... 但我真的不明白为什么下面的代码无法工作:

#include <stdlib.h>
#include <stdio.h>

//unsigned long a = "string"[0] > '0'; // this does not compile
unsigned long a = 's' > '0'; // this works fine, output is "a = 1"

int main(void)
{
    printf("a = %lu\n",a);

    return 0;
}

为什么带有字符串文字的行会给出错误:initializer element is not constant。字符串文字不被视为常量吗? 有没有办法使其运作?

提前感谢。


相关 https://dev59.com/U2855IYBdhLWcg3wKxHc - Ilja Everilä
1
“常量”是一个模糊的术语。C语言使用了几个相关的概念。你需要的是常量表达式。像something[other]这样的下标表达式永远不是常量表达式。 - n. m.
1
请提供一些背景故事的细节,因为这很可能是 XY 问题 - Ruud Helderman
我想使用一个自定义宏,从__DATE__和__TIME__计算出Unix时间戳,并将该值分配给文件范围内的全局变量。简单的解决方法是将该变量隐藏在函数中,但我认为这很丑陋,而且我很好奇为什么它不能编译。 - G. Communithings
2个回答

9
你的变量具有静态存储期,根据N1570(C11)§6.7.9/p4要求,对于具有静态或线程存储期的对象的初始化表达式应为常量表达式或字符串字面值。
字符串字面值具有静态存储期§6.4.5/p6,因此它们的地址可以被视为常量表达式(这就是为什么它们被允许作为初始化器的原因)。但是,您正在尝试访问这种地址处的值,而C标准明确禁止这样做。引用§6.6/p9,我强调了以下部分:
“地址常量是空指针、指向具有静态存储期的对象的左值的指针或指向函数指示符的指针;它必须使用一元运算符&或将整数常量转换为指针类型显式创建,或通过使用数组或函数类型的表达式隐式创建。可以在创建地址常量时使用下标[]、成员访问.和->运算符、地址&和间接*一元运算符以及指针转换,但不得使用这些运算符来访问对象的值。
另一方面,当您使用字符常量进行比较时,您会获得有效的常量表达式。

字符串字面量具有静态存储期。你能引用标准吗? - user694733
1
@user694733 - 请参阅§6.4.5/p6以获取字符串字面值的定义。它们都是静态存储期数组的替代品,其中包含了字面内容。 - StoryTeller - Unslander Monica
我对这个问题提出了不同的看法。如果有遗漏的地方,我会将其删除。希望你不介意。 - user2736738
@coderredoc 他为什么会介意?你不必问! - machine_1
@coderredoc - 我一直主张答案多样性。这是SO的优势之一。 - StoryTeller - Unslander Monica
显示剩余2条评论

4

在C语言中,具有静态存储期的对象必须使用常量表达式或包含常量表达式的聚合初始化器进行初始化。

现在你基本上有"string"[0]作为常量表达式?但是真的吗?

事实是,在6.6p2中:

常量表达式可以在翻译时而不是运行时进行评估,并且因此可以在任何可以使用常量的地方使用。

之后,我检查了翻译阶段及其组成部分:很明显,涉及字符串字面值的[]数组下标操作的表达式都没有被评估。这实际上涉及到解引用地址并获取值,这在翻译阶段是不可能做到的。这就是为什么会出现这个错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接