Перейти к содержанию
    

Взаимопреобразование указателя на структуру и на ее первый член и strict aliasing в Си

Полистал я стандарт, как-то мутновато описано. В упрощенном виде опишу затею.

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

typedef struct {
  u32 type;
  
  float f;
  int   i[10];
} S0;

typedef struct {
  u32 type;
  
  char const *name;
} S1;

typedef struct {
  u32 type;
  
  double d;
  char const *name;
  u32    u;
} S2;

...

S0 s0 = {0, ...};
S1 s1 = {1, ...};
S2 s2 = {2, ...};
...


Как видно, у них у всех имеется в начале u32 type. Язык Си пишет вот что (6.7.2.1)

Цитата

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

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

Теперь, я собираю в кучу-массив указатели на эти структуры: явно это сделать не получится, поэтому можно через тип первых членов

u32 *array[] = {
  &s2.type,
  &s0.type,
  &s1.type,
  ...
};


Теперь мне из внешнего мира, в run-time прилетает "индекс", по которому я лезу в этот массив и должен обратиться к объемлющей структуре, к любым ее полям

u32 num = get_num();
u32 *p = array[num]; // получили указатель на начало какой-то структуры в памяти, а дальше парсим ее

switch(*p) {
    ...
    case 1:
      printf("%s", ((S1 *)p)->name); // вот - преобразую "обратно" - из указателя на u32 в указатель на структуру, чей первый член есть u32, все законно
    ...
}


Однако не совсем законно это с точки зрения правил псевдонимов, вроде как. Как тогда реализовать динамический парсинг структур, когда заранее не известен порядок указателей в массиве? Корректно с точки зрения правил Си.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почитайте, как сделано объектно-ориентированное программирование на C и наследование в частности в Glib/GTK. Т.е. как устроен GObject и как он используется. Например, немного понять суть можно по этому вопросу https://stackoverflow.com/questions/48306127/gobject-and-inheritance

Мне кажется вы пытаетесь изобрести нечто подобное, только намного более простое. Но подход должен быть тот же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 минут назад, makc сказал:

Почитайте, как сделано объектно-ориентированное программирование на C и наследование в частности в Glib/GTK. Т.е. как устроен GObject и как он используется. Например, немного понять суть можно по этому вопросу https://stackoverflow.com/questions/48306127/gobject-and-inheritance

Мне кажется вы пытаетесь изобрести нечто подобное, только намного более простое. Но подход должен быть тот же.

Об этих библиотеках я читал. Однако очень много исходного кода написано так, что он едва ли гарантированно написан переносимым между компиляторами. В Си полно тонкостей со всякими "эффективными типами" и допустимыми способами доступа к объектам, и шаг влево - и получается неопределенное поведение. И в большинстве случаев компилятор правильно сгенерирует код даже в случае наличия UB, и в этом и проблема - грабли лежат, а не видны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, Arlleex сказал:

Об этих библиотеках я читал. Однако очень много исходного кода написано так, что он едва ли гарантированно написан переносимым между компиляторами.

Подход более чем переносим, т.к. его гарантирует правильно выравнивания начала структуры в С. И посмотрите список поддерживаемых архитектур в том же Debian, к вопросу о переносимости.

7 минут назад, Arlleex сказал:

В Си полно тонкостей со всякими "эффективными типами" и допустимыми способами доступа к объектам, и шаг влево - и получается неопределенное поведение. И в большинстве случаев компилятор правильно сгенерирует код даже в случае наличия UB, и в этом и проблема - грабли лежат, а не видны.

Здесь такого нет. Поэтому GObject везде себя прекрасно чувствует.

Ok, если примера Glib/GTK недостаточно, то есть ещё http://libcello.org/ 😎

Погуглите еще "Object-Oriented Programming with ANSI C".

21 минуту назад, Arlleex сказал:

правильно сгенерирует код даже в случае наличия UB, и в этом и проблема - грабли лежат, а не видны.

К вопросу об UB - https://stackoverflow.com/questions/68162979/is-casting-glib-gtk-pointers-undefined-behavior

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/17/2024 at 1:06 AM, Arlleex said:
u32 *array[] = {
  &s2.type,
  &s0.type,
  &s1.type,
  ...
};

 

А если в процессе эволюции программы появиться какой-то новый элемент структуры перед элементом type ?

On 7/17/2024 at 1:06 AM, Arlleex said:

 Как тогда реализовать динамический парсинг структур, когда заранее не известен порядок указателей в массиве? Корректно с точки зрения правил Си.

А вы разве элемент type ввели не ради того, чтобы знать какую именно структуру вы сейчас обрабатываете ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, makc сказал:

Подход более чем переносим, т.к. его гарантирует правильно выравнивания начала структуры в С. И посмотрите список поддерживаемых архитектур в том же Debian, к вопросу о переносимости.

Здесь такого нет. Поэтому GObject везде себя прекрасно чувствует.

Ну в большинстве случаев вопрос поддерживаемой архитектуры не совсем корректен, т.к. он в конечном итоге сводится к конкретному компилятору: опять же, чаще всего это будет GCC.

Поэтому я и говорю, что очень много OpenSource кода написано в стиле "проверено в GCC, там работает и точка".

Цитата

Ok, если примера Glib/GTK недостаточно, то есть ещё http://libcello.org/ 😎

Спасибо, посмотрю.

2 часа назад, makc сказал:

Погуглите еще "Object-Oriented Programming with ANSI C".

Честно сказать, мало какая статья написана настолько грамотно, с отсылками к пунктам стандарта языка. В большинстве случаев я вижу "ну, вот код, который работает, потому что он работает". Вопросы семантики и поведения там не затрагиваются, всякие strict aliasing и UB при приведениях указателей разных типов, для бОльшей части рядовых программистов - вообще "впервые слышу".
 

1 час назад, dimka76 сказал:

А если в процессе эволюции программы появиться какой-то новый элемент структуры перед элементом type ?

Не появится. Зачем мне стрелять себе в ногу? Я читаю стандарт: он мне явно говорит, что указатель на структуру можно безопасно привести к указателю на его первый элемент, и наоборот. Вот только это несколько противоречит пункту, где описано, как можно получить доступ к объекту какого-то определенного типа:

Цитата

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

- a type compatible with the effective type of the object,

- a qualified version of a type compatible with the effective type of the object,

- a type that is the signed or unsigned type corresponding to the effective type of the object,

- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

- a character type.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/17/2024 at 9:58 AM, Arlleex said:

Не появится.

Все так говорят :wink:

On 7/17/2024 at 9:58 AM, Arlleex said:

Зачем мне стрелять себе в ногу?

Так, может быть, взяв таким образом указатель на структуру вы уже это сделали ? :mosking:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

31 минуту назад, dimka76 сказал:

Так, может быть, взяв таким образом указатель на структуру вы уже это сделали ? :mosking:

Каким образом?

Я задал вопрос на стековерфлоу - часть гур сошлась во мнении, что это UB, часть - что это определенное поведение. И вот еще.

Нужна истина.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/17/2024 at 10:22 AM, Arlleex said:

Каким образом?

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

Не вы это сделаете, так кто-то другой, кому достанется ваш проект.

Да и все время держать в голове, что вот этот type должен стоять здесь намертво, тоже не дело. Сколько всего надо держать в голове. Всего не удержишь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 минут назад, dimka76 сказал:

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

Не вы это сделаете, так кто-то другой, кому достанется ваш проект.

Да и все время держать в голове, что вот этот type должен стоять здесь намертво, тоже не дело. Сколько всего надо держать в голове. Всего не удержишь.

Да с таким подходом и никаких эмулирований ООП в Си нельзя было бы делать, в т.ч. ту самую Glib/GTK))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...