Стандарты
В стандарте C ++ 98 есть некоторая информация в
C.2.4.1 Макрос offsetof
( тип , memberdesignator ) [diff.offsetof]
Макрос offsetof
, определенный в <cstddef>
, принимает ограниченный набор аргументов типа в этом международном стандарте.§18.1 описывает изменение.
(C.2.4.1 обнаружился с offsetof
в содержании, поэтому я пошел туда первым.) И:
§18.1 Типы 18 Библиотека поддержки языков
¶5 Макрос offsetof
принимает ограниченный набор аргументов типа в этом международном стандарте. type должен быть структурой POD или объединением POD (раздел 9).Результат применения макроса offsetof к полю, являющемуся статическим элементом данных или элементом функции, не определен.
Для сравнения, стандарт C99 гласит:
offsetof(type, member-designator)
, который расширяется до целочисленного константного выражения, имеющего тип size_t
, значение которого является смещением в байтах, до элемента структуры (обозначенного member-обозначение ) с начала его структуры(обозначается тип ). тип и обозначение элемента должно быть таким, чтобы при заданном
static type t;
выражение &(t.member-designator)
преобразовывалось в адресную константу.(Если указанный член является битовым полем, поведение не определено.)
Ваш код
Ваш код соответствует требованиям стандартов C ++ и C,мне кажется.
Когда я использую G ++ 4.1.2 и GCC 4.5.1 в RedHat (RHEL 5), этот код без жалоб компилируется с параметрами -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
.
Предполагая, что в вашем коде нет блокировок, мне кажется, что вы, вероятно, нашли ошибку в <cstddef>
(или <stddef.h>
) заголовок на вашей платформе.Вы не должны получать сообщение об ошибке, и G ++ на основе Linux подтверждает это.
Временные решения?
Вам нужно будет пересмотреть, как 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 году, я столкнулся с компилятором C, который не позволял бы 0, но вместо этого позволял бы 1024.Разданный заголовок <stddef.h>
, конечно, использовал 0
, поэтому я «исправил» его, изменив значение 0 на 1024 (дважды) на время (пока я не получил лучший компилятор на лучшей машине).