Мне нужно получить адреса объекта по адресу члена этого объекта. Планирую это делать через offsetof.
1) Есть ли другие способы ?
2) Я не совсем понял в описании кажется, что с ним будут проблемы в C23 ? Насколько надёжно и правильное это решение ?
3) gcc генерирует warning если в классе есть виртуальные функции. Но код генерирует правильный с учётом указателя на v-table. В чём тут дело ?
// gcc v4.8 Linux
warning: invalid access to non-static data member ‘MyClass::a’ of NULL object
// gcc v10.2 Windows
warning: 'offsetof' within non-standard-layout type 'MyClass' is conditionally-supported [-Winvalid-offsetof]
printf("%u \n", offsetof(MyClass, a));
class MyClass {
public:
virtual void Test1() {};
UPTR a;
int b;
int c;
};
Здравствуйте, maks1180, Вы писали:
M>Мне нужно получить адреса объекта по адресу члена этого объекта. Планирую это делать через offsetof. M>1) Есть ли другие способы ? M>2) Я не совсем понял в описании кажется, что с ним будут проблемы в C23 ? Насколько надёжно и правильное это решение ? M>3) gcc генерирует warning если в классе есть виртуальные функции. Но код генерирует правильный с учётом указателя на v-table. В чём тут дело ?
Макрос offsetof работает в классах со стандартной разметкой.
При добавлении виртуальных функций, а ещё с возможностью множественного наследования компилятору сложно определить, что вам нужно
Как мне кажется лучшим вариантом будет найти способ убрать виртуальную функцию где требуется offsetof.
Или пользоваться только компиляторами поддерживающими данную функциональность если нет другого варианта.
M>>Мне нужно получить адреса объекта по адресу члена этого объекта. Планирую это делать через offsetof. M>>1) Есть ли другие способы ? M>>2) Я не совсем понял в описании кажется, что с ним будут проблемы в C23 ? Насколько надёжно и правильное это решение ? M>>3) gcc генерирует warning если в классе есть виртуальные функции. Но код генерирует правильный с учётом указателя на v-table. В чём тут дело ?
_NN>Макрос offsetof работает в классах со стандартной разметкой. _NN>При добавлении виртуальных функций, а ещё с возможностью множественного наследования компилятору сложно определить, что вам нужно
Я не пойму в чём проблема если у класса есть фиртуальная функция? разница лишь только в том, что в начале класса добавляется указатель на v-table, все переменные класса сдвигаются на размер указателя.
Здравствуйте, Евгений Музыченко, Вы писали:
M>>Мне нужно получить адреса объекта по адресу члена этого объекта.
ЕМ>Из-за чего такое извращение?
Такое извращение используется в ядре линукса и считается нормой.
В С++ такое можно использовать только к POD структурам, что бы не связывать руки компилятору в его сомнительных оптимизациях.
Re[3]: Получение адреса объекта по адресу члена этого объект
Здравствуйте, maks1180, Вы писали:
M>Я не пойму в чём проблема если у класса есть фиртуальная функция? разница лишь только в том, что в начале класса добавляется указатель на v-table, все переменные класса сдвигаются на размер указателя.
Есть некоторые кейсы, при которых offsetof не может корректно отработать. Сразу приходит на ум виртуальное наследование.
Да, это экзотика, которая редко встречается, но это вполне легальная часть C++. И компиляторы обычно ругаются на попытку применить offsetof к таким классам.
Можно придумать примерно такой кейс:
#include <cstdio>
struct Base
{
virtual ~Base() {}
int m_val;
};
struct Left : virtual Base
{
void showOffset()
{
printf("%zu\n", (size_t)&m_val - (size_t)this);
}
};
struct Right : virtual Base
{
};
struct Child : Left, Right
{
};
int main()
{
Left left;
left.showOffset();
Child child;
child.showOffset();
return 0;
}
Clang и GCC выводят 16 и 24. MSVC — 8 и 12. Ну т.е. offset от 'Left' до 'm_val' здесь зависит от того, как класс Left
включен в наследование — при виртуальном наследовании эта информация должна вычисляться динамически, т.е. в рантайме.
Здравствуйте, kov_serg, Вы писали:
_>Такое извращение используется в ядре линукса и считается нормой.
Это может быть нормой по отношению к структуре, но не объекту. Поскольку в ядре Linux нет кода на C++, то и объектов в обсуждаемом смысле тоже нет.
_>В С++ такое можно использовать только к POD структурам, что бы не связывать руки компилятору в его сомнительных оптимизациях.
К объектам это не должно применяться прежде всего потому, что в С++ такие операции делаются по-другому.
Re[4]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>К объектам это не должно применяться прежде всего потому, что в С++ такие операции делаются по-другому.
Так я и не спорю. В C++ многое через одно место сделано.
Re[5]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, kov_serg, Вы писали:
ЕМ>>К объектам это не должно применяться прежде всего потому, что в С++ такие операции делаются по-другому.
_>В C++ многое через одно место сделано.
Хм, что именно в C++ сделано "через одно место" применительно к данному вопросу?
Re[6]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
_>>В C++ многое через одно место сделано. ЕМ>Хм, что именно в C++ сделано "через одно место" применительно к данному вопросу?
Многое. Например: объявление приватных членов классов в заголовочных файлах.
указатели, на замыкания, на виртуальные методы, на поля класса, битовые поля.
сокрытие реализации там где не надо, но при этом выворачивание наружу костылей компилятора
Re[7]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, kov_serg, Вы писали:
_>Например: объявление приватных членов классов в заголовочных файлах.
Какое это имеет отношение к C++? Традиционный компилятор C++ вообще ничего не знает о "заголовочных файлах", он тупо обрабатывает файлы, поданные ему на вход. А уж как там организованы объявления/определения — дело программиста.
_>указатели, на замыкания, на виртуальные методы, на поля класса, битовые поля.
Где в C++ указатели на битовые поля, и в чем проблема с остальным?
Re[8]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
_>>Например: объявление приватных членов классов в заголовочных файлах. ЕМ>вообще ничего не знает о "заголовочных файлах"
Ну ну.
_>>указатели, на замыкания, на виртуальные методы, на поля класса, битовые поля.
ЕМ>Где в C++ указатели на битовые поля, и в чем проблема с остальным?
Нет единообразия каждый раз изобретают новые костыли.
Re[9]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Так что он, по-Вашему, знает о них?
precompiled headers
_>>Нет единообразия каждый раз изобретают новые костыли. ЕМ>Что единообразия нет — согласен. А костыли последние лет десять изобретают в основном для "метапрограммирования", которое в С++ давно пошло вразнос.
Так оно поэтому в разнос и идёт.
Re[11]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
_>>precompiled headers ЕМ>Это не входит в спецификацию языка, не является обязательным к реализации в компиляторе, и не влияет на его логику по отношению к программе.
Это очень печально что такие важные темы не входят в спецификацию. Тем не менее объявление приватных членов класса в том виде что есть в c++ это грандиозный факап, который был заложен изначально и никто исправлять это даже не планирует. Более того любой фанат c++ так же как и вы будет тыкать в стандарт и не понимать о чем речь.
Здравствуйте, kov_serg, Вы писали:
_>Это очень печально что такие важные темы не входят в спецификацию.
Что именно Вы считаете важным? Операция #include, что в C, что в C++, тупо вставляет вместо себя какой-то файл, и не более того. У нее нет иного назначения, кроме как позволить собрать текст, подлежащий обработке компилятором, из нескольких файлов вместо одного. Понятие "заголовочный файл" — просто соглашение, традиция, как и использование для него расширения ".h". С тем же успехом в основном файле (.c/.cpp) может быть только определение самого класса, а #include может использоваться для включения определений методов из других файлов.
Если хочется установить для этих файлов другие функции и порядки — нужны и другие языковые средства, вроде модулей.
_>объявление приватных членов класса в том виде что есть в c++ это грандиозный факап, который был заложен изначально и никто исправлять это даже не планирует.
С какой целью его следовало бы исправлять? Это не обязанность, а право программиста. Если он делает простую короткоживущую программу, в этом нет никакой опасности. Если он делает сложную программу, которую долго будут сопровождать другие, то может использовать соответствующие языковые средства.
Исправлять имеет смысл то, что невозможно (или слишком сложно) обойти. Вы еще предложите убрать из C++ reinterpret_cast, function-style и C-style cast.
_>любой фанат c++ так же как и вы будет тыкать в стандарт и не понимать о чем речь.
Я ни разу не фанат ни C, ни C++, к обоим у меня куча претензий на протяжении десятков лет. Но пока C++, с учетом опыта и привычки, для моих задач остается наименьшим злом, а использование для этих задач других языков создаст мне еще больший геморрой.
Re[4]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, Евгений Музыченко, Вы писали:
M>Мне нужно получить адреса объекта по адресу члена этого объекта
_>>Такое извращение используется в ядре линукса и считается нормой.
ЕМ>Это может быть нормой по отношению к структуре, но не объекту.
А что такое адрес структуры?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Получение адреса объекта по адресу члена этого объекта
M>Мне нужно получить адреса объекта по адресу члена этого объекта. Планирую это делать через offsetof. M>1) Есть ли другие способы ?
Без UB способов нет, хоть с vtable, хоть без 🤡
Re: Получение адреса объекта по адресу члена этого объекта
кастуй этот указатель в указатель на класс,
вызывай любой виртуальный метод класса который вернет заведомо известный тебе результат, сравнивай её результат с образцом,
оберни этот код try-catch для ловли исключений, в случае если произошло исключение сдвинь указатель еще на пару байт,
и так в цикле пока не получишь правильный результат от функции
таков путь