LINUX.ORG.RU

[C++] конвертация указателя на член класса в целое

 


0

1

Сабж. Есть скажем что то вроде

struct C1{
   double x; 
   int p[4];
};

struct C2{
  char a;
  C1 c;
  C1 cs[12];
};

нужно например узнать смещение С2::с.x относительно начала C2. Или смещение С2::cs[3].p[1]

Сейчас использую конструкции вроде

template <class C,class T> long addr( T C::* p, int i=0 ){ 
    C s; 
    return (char*)&(s.*p)-(char*)&s+sizeof(T)*i; 
}
Но меня терзают смутные сомнения... как бы это сделать Ъ, и что б еще оно и смотрелось нормально при использовании?

★★★★★

Простите, что влезаю не в свое дело (так как Си++ не знаю толком), но все же не могу удержаться и спрошу: разве память для struct всегда выделяется последовательно? А массив p[4] у вас разве не в другой области памяти будет выделен?

delete83 ★★
()
Ответ на: комментарий от delete83

Я вот к чему клоню. Сдается мне, что вы решаете задачу, которая возникла у вас только в силу неправильной постановки задачи. Скорее всего можно переписать алгоритм и обойтись без вывертов с памятью.

delete83 ★★
()
Ответ на: комментарий от delete83

Наск я знаю - не в другой.

Вообще ответ очень ЛОР-вский;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от delete83

разве память для struct всегда выделяется последовательно?

Да, но с учетом выравнивания.

А массив p[4] у вас разве не в другой области памяти будет выделен?

Не будет.

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Спасибо, про него не знал.

Работает, но верещит (варнинги). И элемент массива я не понял как им дергать ;-(

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Легко. Держи тесты:

/* offsetof example */
#include <stdio.h>
#include <stddef.h>

struct C1{
   double x; 
   int p[4];
};

struct C2{
  char a;
  C1 c;
  C1 cs[12];
};

int main ()
{
  printf ("offsetof C2::cs[3] is %d\n",offsetof(C2,cs[3]));
  printf ("offsetof C1::p[1] is %d\n",offsetof(C1, p[1]));
  printf ("offsetof C1::p is %d\n",offsetof(C1, p));
  printf ("offsetof C2::c is %d\n",offsetof(C2, c));
  printf ("offsetof C2::cs[3].p[1] is %d\n",offsetof(C2,cs[3])+offsetof(C1, p[1]));
  
  return 0;
}

Тут хорошо видно, что offsetof даже учитывает выравнивание, которое в данном случае имеет место (на моем компьютере).

delete83 ★★
()
Ответ на: комментарий от delete83

Да, спасибо, с массивами оно и правда работает, а вот ворнинги сыпятся если хотя бы одно поле имеет пользовательский конструктор по умолчанию... Ну и доступ к элементам массива через перегруженный оператор [] ес-но не работает, чудес не бывает;-(

Ну тем не менее это наверное более тру чем мой вар с чарами, щас во что нить его завернем;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

а вот ворнинги сыпятся если хотя бы одно поле имеет пользовательский конструктор по умолчанию

Насколько я помню, структуры в этом случае перестают быть POD-типами, и с Си-магией на примере offsetof могут случаться косяки

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Похоже на то. А насколько плох вариант с чарами

template <class C,class T> long addr( T C::* p, int i=0 ){ 
    C s; 
    return (char*)&(s.*p)-(char*)&s+sizeof(T)*i; 
}
чем он вообще череват?

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

есть компилеры, которые для классов с нетривиальными деструкторами нарушают инвариант что адрес первого элемента массива == начало блока памяти для него. То есть ваш способ где-то на грани между implementation dependent и undefined behavior, которую на практике придется тщательно проверять тестами с каждой конкретной версией компилятора. Для легализации вам лучше разделить структуры по которым дергаются оффсеты и классы поверх них с конструкторами и тп с++ стаффом. Тогда получив правильный адрес начала структуры в ней можно будет «законно» получать поля по смещениям.

sleepy
()
Ответ на: комментарий от sleepy

Именно деструкторы? Деструкторы у меня как раз тривиальные, целевые классы невиртуальные... актуальные компиляторы gcc и mingw

AIv ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

Насколько я помню, структуры в этом случае перестают быть POD-типами, и с Си-магией на примере offsetof могут случаться косяки

Правильно помнишь.

LamerOk ★★★★★
()
Ответ на: комментарий от sleepy

есть компилеры, которые для классов с нетривиальными деструкторами нарушают инвариант что адрес первого элемента массива == начало блока памяти для него

Этот инвариант в общем случае не применим к любым не POD структурам данных. Его соблюдение - частный случай конкретного компилятора.

LamerOk ★★★★★
()
Ответ на: комментарий от AIv

Именно деструкторы?

Нет. Просто компилятору сейчас много позволено для не POD типов. Я бы не стал смешивать классы для работы и более постоянные форматы хранения. Ну и дергать одно поле напрямую сейчас смысла нет - память то совсем не random access по скоростным характеристикам.

То есть кратко ответов 2 - 1)это не надо делать. 2)если все равно хочется, то делать для структур, а классы навешивать на них например приватным наследованием.

sleepy
()

конвертация указателя на член класса в целое

ССЗБ.

anonymous
()
Ответ на: комментарий от sleepy

Напрямую приходится дергать поскольку иначе там код совсем заморочный будет. Есть массив (многомерный) каких то объектов. Надо сэмулировать массив аналогичной размерности, состоящий из поля этих объектов, так что бы доступ к полю был напрямую (на чтение и запись). Как это по другому сдлеать, кроме как фокусов с адресной арифметикой, я не знаю... поскольку параметризовать что то то указателю на член дико неудобно.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

С классами иначе. Там ещё есть (в памяти) таблица виртуальных функций с возможными вытекающими отсюда проблемами.

invy ★★★★★
()
Ответ на: комментарий от invy

Класс от структуры вообще то отличается только дефолтным доступом к членам. Таблица есть только у виртуальных классов (структур).

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Пока виртуальных функций нет - да. Но они могут потом появиться, в любой момент, при том позже, когда вы о своём шаманстве забудете, или вы будете в комментарии писать «СЮДА ВИРТУАЛЬНЫЕ ФУНКЦИИ НЕ ДОБАВЛЯТЬ - ВСЁ ПОЛОМАЕТСЯ»?

invy ★★★★★
()

А может не надо?

Если в подобной задаче хоть какая-то целесообразность? Мне кажется, что Ъ-путь, это вообще так не делать.

pathfinder ★★★★
()
Ответ на: комментарий от invy

У наших задач такая специфика, что виртуальные ф-ии вообще используются крайне редко, а на этом уровне никогда.

AIv ★★★★★
() автор топика
Ответ на: А может не надо? от pathfinder

Если в подобной задаче хоть какая-то целесообразность?

Есть.

Мне кажется, что Ъ-путь, это вообще так не делать.

Мне кажется, что Ъ-путь это вообще не рассуждать о целесообразности задач, которые не описаны подробно вместе с контекстом (откуда именно такая задача возникла и что ее решение автору дает). Хотя на ЛОРе это и очень принято... Вы уже третий такой в этой ветке;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Не ну просто просто можно же отсабклассить структуру... тогда таких проблем не будет в принципе.

invy ★★★★★
()
Ответ на: комментарий от AIv

Ъ-путь это вообще не рассуждать о целесообразности задач, которые не описаны подробно вместе с контекстом

На текущий момент я глубоко убежден в том, что не существует такой задачи, где подобное целесообразно. По этому и интересно. Может расскажешь, что ты там собираешься делать. Обещаю не писать комментарии в духе «Вася, ты не прав!». :)

pathfinder ★★★★
()
Ответ на: комментарий от AIv

раз так сильно хочется, то в таком случае делайте структуру из всех так адресуемых полей, наследуйте от нее класс. По индексам находите экземпляр, из него адрес структуры (он не совпадет в общем случае) и уже потом оффсеты.

Производительность такого решения будет реально слабее чем без этих фокусов. Для скорости (если надо) стоит располагать те части что используются вместе в соседних ячейках памяти.

sleepy
()
Ответ на: комментарий от pathfinder

Есть библиотека шаблонов, реализующая в частности массив произвольной размерности (под размерностью понимается число индексов, необходимых для доступа к элементу, а не размер массива). В ряде случаев требуется обрабатывать отдельные поля элементов - скажем сохранить в файл все поля a, считать из файла все поля b, построить массив из прлей c, поменять ему местами очи и вырезать из него кусок, и т.д Критичной является производительность, простота использования конечным пользователем ну и не слишком заморочная реализация. Ручная работа с адресами (смещениями) позволяет все это делать, причем на все случаи жизни у меня один класс массива, парметризованный по типу элемента и размерности (на самом деле не один, поскольку существует неск вариантов расположения данных в многомерном массиве + есть коллекции массивов и т.д.).

AIv ★★★★★
() автор топика
Ответ на: комментарий от sleepy

Не получится, это же библиотека... откуда я знаю, какие там будут поля и типы элементов? Да и слишком громоздко.

Пока я никаких серьезных против арифметки с чарами не увидел. И да, вирт таблица так тоже должна учитываться наск я понимаю...

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

а offsetof не так же реализован?

Он делает то же, только, по определению, делает это правильно ;)

const86 ★★★★★
()
Ответ на: комментарий от Slavaz

не NULL, а 0. NULL == 0 не всегда верно.

p.s. капча $800,000 как бы намекает сколько денег ты мне теперь должен.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.