关注此问题Why doesn't gcc allow a const int as a case expression?,与What promoted types are used for switch-case expression comparison?或Is there any way to use a constant array with constant index as switch case label in C?基本相同。
从第一个链接开始,我尝试替换:
case FOO: // aka 'const int FOO = 10'
with:
case ((int) "toto"[0]): // can't be anything *but* constant
给出了:
https://ideone.com/n1bmIb - > https://ideone.com/4aOSXR =适用于C ++
https://ideone.com/n1bmIb - > https://ideone.com/RrnO2R =在C
中失败我不太明白,因为" toto" string不能是但是是一个常量,它甚至不是一个变量,它位于编译器内存的空白之中。我甚至没有玩过' const' C语言的模糊逻辑(实际上代表"只读,不是常数,你期望什么?"),问题是"数组访问"或"指针引用"转换为不在C中求值的常量表达式,但在C ++中表现很好。
我希望用这个"技巧"使用HASH_MACRO(str)从密钥标识符生成唯一的case标签值,最终使编译器在发生冲突时引发错误,因为找到了类似的标签值。
好的,好的,我被告知这些限制是为了简化语言工具(preproc,编译器,链接器)和C ain没有LISP,但你可以拥有全功能的LISP解释器/编译器,只需一小部分C等价物的大小,所以没有任何借口。
问题是:是否有"扩展"到C11只允许这个" toto"在GCC,CLANG和... MSVC工作?我不想去C ++路径(typedef'前向声明不再工作)和嵌入式东西(因此编译时哈希计算用于时空失真)。
是否有中间人" C +"更加宽容的语言'并且“了解'嵌入式更好一点,比如-Praise the Lords-" enums as bitfield members&#34 ;,在我们不能拥有的其他很好的东西中(因为现实标准像沙漠太阳下的蜗牛一样发展)?
#provemewrong,#changemymind,#norustplease
答案 0 :(得分:6)
在编译时编译器是否可以知道它并不重要。 case
标签需要具有整数常量表达式 (C11 6.8.4.2p3)的值。
- 每个
醇>case
标签的表达式应为整数常量表达式,并且同一switch语句中的两个case常量表达式在转换后不应具有相同的值。 switch语句中最多可能有一个默认标签。 (任何封闭的switch语句都可以有一个默认的标签或case常量表达式,其值可以在封闭的switch语句中复制case常量表达式。)
整数常量表达式的定义是in C11 6.6p6:
- 整数常量表达式应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的
醇>sizeof
表达式,_Alignof
表达式和浮动常量是演员的直接操作数。整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof
或_Alignof
运算符的操作数的一部分。
由于"toto"
不是整数常量,枚举常量,字符常量,常量sizeof
,_Alignof
表达式或浮点常量强制转换为整数;并且该列表在标准的约束部分中指定,编译器不能以静默方式传递。 (即使是符合标准的编译器仍然可以成功编译程序,但它必须将其诊断为违反约束。)
您可以使用链接? :
来将索引解析为字符常量,即
x == 0 ? 't'
: x == 1 ? 'o'
: x == 2 ? 't'
: x == 3 ? 'o'
这可以写入宏。
答案 1 :(得分:2)
"toto[0]"
不是整数常量表达式,因为C定义了术语:
6.6常量表达式
...
6整数常量表达式 117)应具有整数类型,并且只能有操作数 它是整数常量,枚举常量,字符常量,sizeof
结果为整数常量,_Alignof
表达式和浮点数的表达式 作为强制转换的直接操作数的常量。将运算符转换为整数常量 expression只能将算术类型转换为整数类型,除非作为一部分 操作数为sizeof
或_Alignof
运算符。 117)在许多上下文中需要整数常量表达式,例如位域的大小 结构的成员,枚举常量的值和非可变长度的大小 阵列。适用于条件包含中使用的整数常量表达式的其他约束 预处理指令在6.10.1。中讨论
答案 2 :(得分:0)
你遇到的问题是,在C中,“toto”是一个字符数组。当然,它在内存中是恒定的,但它仍然只是一个数组。 []运算符在数组中索引(来自指针)。如果您愿意,您可以编辑已编译的二进制文件并将字符串“toto”更改为其他内容。从某种意义上说,它不是编译时知道的。这相当于:
char * const ___string1 = "toto";
...
case ((int) ___string1[0]):
(这有点强迫和多余,但它仅用于演示)
请注意,字符串文字的元素类型为char
,而不是const char
。
这种情况必须是常量,因为它内置于编译的程序控制流程中。