GCC 4.4.3偏移常量表达式错误。我应该如何解决这个问题?

时间:2012-02-07 00:32:43

标签: android c++ gcc

我有一个包含静态常量表达式的结构,该表达式使用stddef.h中定义的偏移宏


struct SomeType {

    int m_member;
};

static const size_t memberOffset = offsetof(SomeType, m_member);
GCC 4.4.3中的

(我正在使用Androids NDK r7),这会产生以下错误:


arm-linux-androideabi-g++ -MMD -MP -MF ./obj/local/armeabi-v7a/... -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-exceptions -fno-rtti -O2 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 - -I/Users/Byron/bin/android-ndk-r7/sources/cxx-stl/system/include -
 -Wa,--noexecstack   -O0 -g -w -D_ANDROID   -I/blah/bin/android-ndk-r7/platforms/android-14/arch-arm/usr/include -c  
/MyFile.h:330: error: '->' cannot appear in a constant-expression
/MyFile.h:330: error: '&' cannot appear in a constant-expression

这似乎是一个编译器错误。有没有人有一个很好的解决方法呢?我在GCC 3.4上找到了对这种性质的错误的引用,但后来的版本没有。嗯

2 个答案:

答案 0 :(得分:2)

必须使用指针算法定义

offsetof()。 GCC可能在常量表达式中不喜欢它,因为理论上指针可能会发生变化,因此非const。 解决方法可能是static int没有const

答案 1 :(得分:2)

标准

在C ++ 98标准中,

中有一些信息
  

C.2.4.1宏offsetof类型 memberdesignator )[diff.offsetof]

     

offsetof中定义的宏<cstddef>在此International中接受一组受限制的类型参数   标准。 §18.1描述了变化。

(C.2.4.1在内容中显示offsetof,所以我先去了那里。)并且:

  

§18.118种语言支持库

     

¶5宏offsetof在本国际标准中接受一组受限制的类型参数。   应为POD结构或POD联合(第9条)。将offsetof宏应用于该字段的结果   是静态数据成员或函数成员未定义。

为了比较,C99标准说:

 offsetof(type, member-designator)
     

扩展为类型为size_t的整数常量表达式,其值为   这是结构成员的偏移量(以字节为单位)(由 member-designator 指定),   从其结构的开头(由 type 指定)。 类型成员指示符   应该是给定的

static type t;
     

然后表达式&(t.member-designator)计算为地址常量。 (如果   指定的成员是位字段,行为未定义。)


您的代码

在我看来,您的代码符合C ++和C标准的要求。

当我在RedHat(RHEL 5)上使用G ++ 4.1.2和GCC 4.5.1时,此代码无需使用-Wall -Wextra选项进行编译:

#include <cstddef>

struct SomeType {
    int m_member;
};

static const int memberOffset = offsetof(SomeType, m_member);

它还可以在没有#include <stddef.h>和GCC编译器的情况下进行编译(如果我在宏调用中使用struct SomeType)。

我想知道 - 在我加入<cstddef>之前我遇到了错误...你是否包含了这个错误?当然,我还在声明中添加了int类型。

假设您的代码中没有任何bloopers,我觉得您可能在平台上的<cstddef>(或<stddef.h>)标题中发现了一个错误。你不应该得到错误,基于Linux的G ++似乎证实了这一点。

变通?

您需要查看系统标头中offsetof()的定义方式。然后,您可能会以不会遇到问题的方式重新定义它。

你可能能够使用这样的东西,假设你以某种方式识别你的系统,并执行#define BROKEN_OFFSETOF_MACRO(或在命令行中添加-DBROKEN_OFFSETOF_MACRO)。

#include <cstddef>

#ifdef BROKEN_OFFSETOF_MACRO
#undef offsetof
#define offsetof(type, member)   ((size_t)((char *)&(*(type *)0).member - \
                                           (char *)&(*(type *)0)))
#endif /* BROKEN_OFFSETOF_MACRO */

struct SomeType {
    int m_member;
};

static const int memberOffset = offsetof(SomeType, m_member);

存在size_t强制转换,因为两个地址之间的差异为ptrdiff_toffset()宏定义为返回size_t。宏只是丑陋的,但这就是为什么它通常隐藏在系统标题中,你不必在它的所有可怕性中看它。但是当所有其他方法都失败时,你必须做任何必要的事情。

我知道有一次,大约在1990年,我遇到了一个不允许0的C编译器,但它会允许1024。当然,分布式<stddef.h>标头使用了0,因此我通过将持续时间更改为0到1024(两次)来“固定”它(直到我在更好的机器上获得更好的编译器)。