开关错误:无法出现在常量表达式中。

6

这是一个比较奇怪的问题...

我正在尝试使用一些解压算法。与其通过循环遍历 char buffer[] 直到找到 buffer[i] 中的停止位,我正在尝试使用一些字符掩码技术。

我有以下示例:

// In a *.h file  
const char ch = '\x81';  
// To avoid Endianess  
union CharUInt  
{  
    char sz[4];  
    unsigned int u;  
};  
// Legal because char[] is declared before uint32 in the union  
const CharUInt Mask1 = {'\x81', '\x0', '\x0', '\x81'};  
const CharUInt Mask2 = {'\x0', '\x81', '\x81', '\x0'};  
// Proxy / Auxillary uint32 as usimg Mask2.u in the switch blocked produced the same errors  
const unsigned int uMask1 = Mask1.u;  
const unsigned int uMask2 = Mask2.u;  
const unsigned int uMask_ = (uMask1 & uMask2);  
// buf is always long enough  
bool Foo(char buf[])  
{  
    const CharUInt Type = {buf[0], buf[1], buf[2], buf[3]};  
    unsigned int uType = (Type.u & uMask_);  
    switch(uType)  
    {  
    case uMask1:  
        // do stuff  
    case uMask2:    
        // do more stuff  
        return true;  
        break;  
    default:  
        // do different stuff  
        return false;  
        break;  
    }  
};  

不考虑“union”语法(实际代码可以编译运行),也不考虑“Foo”函数返回是否漂亮,我得到以下错误:
'uMask1' cannot appear in a constant-expression
如果使用联合本身,则会出现以下错误:
'Mask1' cannot appear in a constant-expression
'.' cannot appear in a constant-expression
当然,这些错误也适用于uMask2和Mask2.u。
我错过了什么?
提前感谢。

1
联合声明后面的冒号是有意为之吗? - gregg
你的错误指出了原因。应该用你需要检查的常量数据替换uMask1,而不是uMask1本身。 - DumbCoder
2个回答

6
混淆的原因在于const和const是两个不同的东西。
在switch语句中,case需要“常量表达式”。换句话说:这些表达式可以在编译时由编译器“计算”出来。这可能是一个硬编码的数字(比如42),或者是之前定义为数字的东西(使用#define)。
Const还被编译器用作“一旦这个变量有了一个值,它就不会再改变”的意思。例如,在下面的代码中:
void myFunction (const int value)
{
...
}

值将是常量。我将无法更改const的值,但这并不意味着它对编译器来说是“常量表达式”。

在您的情况下,uMask1是const(无法再更改),但不是常量表达式。


但是为什么编译器不能在编译时计算uMask1uMask2的值呢?它拥有所有必要的信息来完成这个任务。 - HelloGoodbye
1
是的,理论上它可以这样做,但编译器不一定会这样做。这就是为什么C++11添加了constexpr关键字。它告诉编译器应该在编译时而不是运行时计算表达式。虽然我在你的情况下尝试过,但似乎并没有帮助 :-( - Patrick

1

case条件表达式必须是整数类型或可转换为整数类型,并且必须是const。

6.4.2 [stmt.switch]

条件应为整数类型、枚举类型或具有单个转换函数到整数或枚举类型的类类型(12.3)。如果条件是类类型,则通过调用该转换函数将条件转换,转换的结果用于本节其余部分中原始条件的位置。执行整数提升。可以使用一个或多个case标签标记switch语句中的任何语句,如下所示:

case constant-expression :

其中constant-expression应为整数常量表达式。整数常量表达式(5.19)隐式转换为switch条件的推广类型。在转换为switch条件的推广类型后,同一switch中的任何两个case常量都不得具有相同的值。

你的表达式不是一个常量表达式,即使变量本身是 const 的,所以你不能使用它来进行开关操作。你需要使用 if 语句。

然而,你还有另一个问题:

你创建了一个 union

union CharUInt  
{  
    char sz[4];  
    unsigned int u;  
};

然后您初始化该联合的sz成员,

static const CharUInt Mask1 = {'\x81', '\x0', '\x0', '\x81'};  

然后您可以访问该联合体的u成员。

static const unsigned int uMask1 = Mask1.u;  

根据标准,这会引发未定义的行为。在标准语言中,联合体的2个成员不能同时处于活动状态。这意味着您不能像转换器一样处理联合体。


嗨John,感谢你的回答。除了为所有可能和有趣的字节顺序做ifdef之外,还有什么方法可以解决这个问题吗?另外,你说“联合体的2个成员不能同时处于活动状态”是什么意思?在代码中实际上是<code>typedef struct _tagType{ union {...}; } TypeT;</code> - globalcouchsurfer

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