在en Studio中使用offsetof无法在Visual Studio 2015

时间:2017-03-10 19:04:51

标签: c windows visual-studio-2013 visual-studio-2015

我有以下代码可以在Visual Studio 2013中编译,但在Visual Studio 2015中没有。 在VS2015上,我收到错误“错误C2057:预期的常量表达式”

#include <stddef.h>    

struct temp {
    int a;
    char b;
};

int main() {
    enum {TEST = (offsetof(struct temp, a)? 1 : 2)};
    return 0;
}

我使用以下命令编译它: cl -nologo -FS -MD -EHsc -Od -D_DEBUG -Zi -c test.c

我查看了stddef.h标头,看起来在VS 2015中,offsetof宏发生了变化。 当我使用CPP标志编译它时,这段代码编译得很好: cl -nologo -FS -MD -EHsc -Od -D_DEBUG -Zi -c test.c -TP

我想知道如何在Visual Studio 2015中使用这段代码。谢谢!

2 个答案:

答案 0 :(得分:1)

简短回答:似乎VS2015编译器错了。

来自标准:

  

7.19p3&#34;

     

宏是      ...

offsetof(type, member-designator)
     

扩展为整数常量表达式

  

6.6p3(常量表达式的约束):常量表达式不应包含赋值,递增,递减,函数调用或逗号运算符,除了...

从下面两个引用中,上面的表达式是一个常量表达式,因此每个兼容的编译器必须接受需要常量表达式的表达式,包括枚举常量的值。

MSVC并未声称符合C标准。实际上甚至不符合标准(C99)的18岁之前版本。因此,它可能不支持offsetof

如果它在C ++中有效则不能证明任何东西;它是一种不同的语言。

增加:

我认为错误源于offsetof。此错误消息显示的一个原因是编译期间未定义宏。 C90编译器将假设它是在不同编译单元中定义的函数(无原型,隐式声明)。这确实会使表达式为非函数调用非常数(参见上面的6.6p3)。我不认为这是条件运算符。

更新

根据@HansPassant的this comment,它是VS2015中宏的一个错误。解决方法是明确比较宏的结果:

(offsetof(struct temp, a) != 0) ? 1 : 2
天气风向标

添加。这是stddef.h

中的MSVC 2015定义
// Define offsetof macro
#if defined(_MSC_VER) && !defined(_CRT_USE_BUILTIN_OFFSETOF)
    #ifdef __cplusplus
        #define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif

我不知道

的重要性
#if defined(_MSC_VER) && !defined(_CRT_USE_BUILTIN_OFFSETOF)

答案 1 :(得分:1)

  

我收到错误“错误C2057:预期的常量表达式”

在这方面,VS似乎不符合要求。它至少应用了对整数常量表达式规则的非常规解释。 MS从未声称它的C实现符合任何版本的标准 - 而且众所周知不会这样做 - 但由于VS2013的做法不同,我认为VS2015的行为是一个错误。

投诉可能与枚举常量TEST的初始值设定项有关。 C要求值具有“integer constant expression”的形式,并且如果其操作数适合,则三元运算绝对可以是整数常量表达式。我认为MSVC拒绝代码是因为使用了offsetof()宏,而是标准expressly specifies,该宏本身扩展为整数常量表达式(该链接指向C2011草案,但所有该标准的先前版本已经说过这个)。

除了常量表达式的一般要求:

  

常量表达式不应包含赋值,增量,   递减,函数调用或逗号运算符,除非它们是   包含在未评估的子表达式中。

     

每个常量表达式应计算为中的常量   其类型的可表示值范围。

整数常量表达式受这些限制的约束:

  

整数常量表达式应具有整数类型且必须   只有整数常量的操作数,枚举常量,   字符常量,sizeof表达式,其结果是整数   常量,_Alignof表达式和浮动常量   即时的演员阵容。将运算符转换为整数常量   表达式只能将算术类型转换为整数类型,   除了作为sizeof或_Alignof运算符的操作数的一部分。

我可以解析所有不允许代码的唯一方法是区分整数常量表达式的允许操作数的“整数常量”和“整数常量表达式”。但是,我不认为这是标准的意图,而且我不知道任何采用这种解释的实现 - 据我所知,甚至MSVC本身也不会在其他情况下采用这种解释。

关于你的实际问题,

  

我想知道如何在Visual Studio 2015中使用这段代码。

,除非struct temp的定义有可能发生变化,否则我会手动评估整个三元表达式。结构的第一个成员的偏移量必须为0,因此我将用

替换您的代码
enum {TEST = 2};

或者,在评论中,@ HansPassant建议使用此解决方法:

enum { TEST = (offsetof(struct temp, a) != 0) ? 1 : 2 };

如果这对您不起作用,那么可用的最佳解决方案可能是使用不同的(版本的)编译器。