我有一个包含静态常量表达式的结构,该表达式使用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上找到了对这种性质的错误的引用,但后来的版本没有。嗯
答案 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_t
,offset()
宏定义为返回size_t
。宏只是丑陋的,但这就是为什么它通常隐藏在系统标题中,你不必在它的所有可怕性中看它。但是当所有其他方法都失败时,你必须做任何必要的事情。
我知道有一次,大约在1990年,我遇到了一个不允许0的C编译器,但它会允许1024。当然,分布式<stddef.h>
标头使用了0
,因此我通过将持续时间更改为0到1024(两次)来“固定”它(直到我在更好的机器上获得更好的编译器)。