【发布时间】:2019-04-08 19:06:43
【问题描述】:
我完全了解switch 语句背后的机制以及为什么需要整数常量。我不明白为什么以下case 标签不被视为整数常量。之后怎么样了?不存在的变量?有人可以分类吗? C 编译器真的有必要这么笨吗?
struct my_struct {
const int my_int;
};
switch (4) {
case ((struct my_struct) { 4 }).my_int:
printf("Hey there!\n");
break;
}
当然……
error: case label does not reduce to an integer constant
case ((struct my_struct) { 4 }).my_int:
编辑回答尤金的评论:
你是什么真正的用例?如果是整数常量,为什么要这么复杂?
我试图找到一个巧妙的技巧来在两个字符串之间切换,使用 union 而不是 struct,如下例所示:
#include <stdio.h>
union my_union {
char my_char[sizeof(int)];
int my_int;
};
void clever_switch (const char * const my_input) {
switch (((union my_union *) my_input)->my_int) {
case ((union my_union) { "hi" }).my_int:
printf("You said hi!\n");
break;
case ((union my_union) { "no" }).my_int:
printf("Why not?\n");
break;
}
}
int main (int argc, char *argv[]) {
char my_string[sizeof(int)] = "hi";
clever_switch(my_string);
return 0;
}
…当然不能编译。
在我的机器上((union my_union) { "hi" }).my_int 是26984
而((union my_union) { "no" }).my_int 是28526。但是我不能自己写这些数字,因为它们取决于机器的字节序(显然我的机器是小端序的)。但是编译器知道后者,并且在编译期间确切地知道((union my_union) { "no" }).my_int 将是什么数字。
烦人的是我可以 已经做到了,但只能使用非常晦涩(而且效率稍低)的语法。下面的例子编译得很好:
#include <stdio.h>
void clever_switch (const char * const my_input) {
#define TWO_LETTERS_UINT(FIRST_LETTER, SECOND_LETTER) ((unsigned int) ((FIRST_LETTER) << 8) | (SECOND_LETTER))
switch (TWO_LETTERS_UINT(my_input[0], my_input[1])) {
case TWO_LETTERS_UINT('h', 'i'):
printf("You said hi!\n");
break;
case TWO_LETTERS_UINT('n', 'o'):
printf("Why not?\n");
break;
}
#undef TWO_LETTERS_UINT
}
int main (int argc, char *argv[]) {
clever_switch("hi"); /* "You said hi!" */
clever_switch("no"); /* "Why not?" */
return 0;
}
所以问题仍然存在:C 编译器(或本例中的 C 标准)真的需要这么笨吗?
【问题讨论】:
-
你的真正用例是什么?如果是整数常量,为什么要这么复杂?
-
在大多数情况下,C 标准不会让编译器在编译期间处理对象。任何编译时评估只需要使用简单的值。与简单值相比,根据定义,对象是一个存储区域,其中字节表示一个值。 C 被设计成,或者至少最初是被设计成便携的和小型的。一个特性是交叉编译:编译器可以设计为在一种架构上运行,并编译程序以在另一种架构上执行。 C 标准对此有各种规定,例如单独的字符集……
-
… 用于编译和执行。所以考虑一个 C 编译器,它必须允许你把东西放在一个结构中然后提取它们,它必须模拟它们如何进入目标系统上的结构,而不是在本机系统上。只需将
int放入并取出,这似乎很简单。但是 C 表达式可能会变得复杂得多。您可以将int放入,然后取出一个字节,使用转换为char *。我们不会要求 C 编译器来模拟它。当然,它可以做一些事情以使其适用于像您这样的简单int操作,但是 C 标准...... -
... 在解释必须以这种方式支持哪些特定事物时会遇到一些麻烦。不支持这种事情更简单。它就足够了——没有这个特性,C 已经取得了巨大的成功。即使你不摆弄字节,考虑一下如果你定义一个巨大的数组,用一些值初始化,然后取出其中一个用作“常量”会发生什么。现在您正在强制编译器在编译时处理大量数据。
标签: c switch-statement