LINUX.ORG.RU

Странные ограничения offsetof

 ,


0

4

C++ 11 и выше накладывает шизанутые ограничения на offsetof: http://en.cppreference.com/w/cpp/concept/StandardLayoutType

Вкратце:

  • смешал любые из двух private/protected/public => non-standard layout
    struct non_std {
      int x;
    private:
      int y;
    };
    
  • виртуальная функция и/или виртуальный базовый класс => non-standard layout
  • используешь ссылки => non-standard layout
    struct non_std {
      int x;
      int &y;
    };
    
  • все нестатические поля должны быть standard layout
  • еще портянка про C++14 и о том, как было плёхо без него

Внимание, вопрос: зачем все это? Ежу понятно, что компилятор каждую структуру располагает в памяти строго фиксированным образом, который зависит лишь от версии компилятора и параметров компиляции (в т. ч. pragma align). То есть, все поля любого класса вне зависимости от его «наполнения» имеют строго определенные оффсеты, которыми можно свободно манипулировать (да, я люблю интрузивные контейнеры из sys/queue.h). Зачем это запрещать?

И не только я считаю, что это полное дерьмо (в головах разработчиков стандарта ofc), порождающее чудовищ: https://gist.github.com/graphitemaster/494f21190bb2c63c5516

Как же быть? Мой ответ:

#define coo1_offsetof(type, field) ((uintptr_t)&((type*)(void*)(uintptr_t)1)->field - 1u)

Удалось ли мне утереть нос секте UB-шников, которые в наши дни пишут компиляторы?

C++ 11 и выше накладывает шизанутые ограничения на offsetof

Вроде практически ничего не поменялось с C++ 98. Просто раньше не было понятия standard-layout, а был только POD, которые aggregates. Ограничения были те же, но POD вроде расширили, поэтому offsetof переопределили через standard-layout.

xaizek ★★★★★
()

ооооо.

то есть когда я говорю, что разрабы компиляторов долбоёпы то это я кругом неправ, а когда аццкий петух за жопу клюнет, то «зачем всё это?»

мешал любые из двух private/protected/public

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

ckotinko ☆☆☆
()
Последнее исправление: ckotinko (всего исправлений: 1)
Ответ на: комментарий от ckotinko

то есть когда я говорю, что разрабы компиляторов долбоёпы то это я кругом неправ, а когда аццкий петух за жопу клюнет, то «зачем всё это?»

Ты меня с кем-то спутал.

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

Эм... Как бы творчески они не подходили, можно получить адрес любого member-а Так, кажется, вижу первый облом: адрес ссылочного поля невозможно получить, ну да и пофиг — нормальные пацаны ссылки за пределами локальных алиасов не используют.

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

ссылка-не ссылка. а какая разница в итоге? у неё есть тип, и по сути ссылка куда-то указывает именно как указатель. она же не волшебная. она из байтов состоит. её нельзя оставить undefined, что-то то там еще нельзя, но она в итоге куда-то указывает и один хер где-то лежит.

вся беда С++ в том, что власть в комитете захватила «академия» и начала толкать «теорию». отсюда эти волшебные превращения «undefined»->«не может быть».

в с++ многие фичи предлагали с начала 2000х годов. move semantics например. но выродки упирались рогом. доупирались до того, что река стала их обтекать по сторонам в виде -std=c++0x. после этого выродки решили, что раз процесс нельзя остановить, значит надо возглавить его и попёрла какая-то содомия безумная(17,20 и т.д.).

ckotinko ☆☆☆
()
Последнее исправление: ckotinko (всего исправлений: 1)

Разыменовывание 1 с точки зрения стандарта настолько же неправильно, как и разыменовывание 0.

Фактически, offsetof — это костыль в си, которым приходилось пользоваться из-за отсутствия указателей на члены. Если добавить к указателям на члены шаблоны, то получается ровно то, что Вам нужно, но безопаснее (так как информация о типах не теряется, а проверяется во время компиляции). Так сделано во всяких boost intrusive.

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

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

«академия» сама себя захватила? страуструп как работал в университете, так и работает.

байтолюбство — это не про кресты, и даже не про си.

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

Они из принципа не хотят что-то понимать.

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

ub в тэгах

Почему я не удивлен, что ты здесь?=)

Dudraug ★★★★★
()
Ответ на: комментарий от kawaii_neko
int data, *pdata = &data, &rdata = data;
printf("%p %p\n", &pdata, &rdata);

А что этот код должен показать? Что у pdata и rdata разные адреса? Так это вроде бы очевидно.

roof ★★
()

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

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

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

я так понимаю, что когда начинаются игры с private/public, они пытаются защитить свою задницу от проблем с реализацией наследования.

Мне кажется, что оно скорее связано с этим:

Non-static data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified. ...

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

А что этот код должен показать? Что у pdata и rdata разные адреса? Так это вроде бы очевидно.

Да, только вот

(&data == &rdata) // == true

Т.к. оператор & для ссылки возвращает адрес обьекта, на который она ссылается. Т.е правильнее было бы написать так:

printf("%p %p\n", pdata, &rdata);

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

сама ссылка, буде она лежит в структуре станет указателем.

Ну вот зачем такие глупости говорить?

Это не глупость, а правда. GCC так делает к примеру: https://wandbox.org/permlink/jhTjPIzqHJ7JHfb5 (конечно пример не идеален, но сойдет).

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

The order of allocation of non-static data members with different access control is unspecified.

А ведь эти private/public существуют только на уровне С++. Т.е. синтаксический сахар. Не вижу адекватных причин так делать (т.е. так писать стандарт).

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

А ведь эти private/public существуют только на уровне С++. Т.е. синтаксический сахар. Не вижу адекватных причин так делать (т.е. так писать стандарт).

final тоже существует только на уровне языка. А изменение порядка может быть полезно, например, для более эффективного выравнивания.

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

ну и с этим тоже. там вообще компилятор волюнтаризмом занимается.

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

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

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

Ну, то есть поведение операторов (не только унарного &, но и, например, бинарного + и инкремента) разное, синтаксис декларации разный, одинаковый только размер (в конкретной реализцаии) и, по решению разработчиков компилятора, внутреннее представление может быть реализовано как адрес. Как из этого следует, что ссылка становится указателем?

roof ★★
()
Последнее исправление: roof (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

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

Когда все работает и никаких проблем, все живут спокойно с обычными структурами. Их никто не запрещал же.

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

то увидим, что оператор & вызванный два раза для одной и той же автоматической переменной,

Ну да, иначе бы вообще все поломалось. Я тогда не улавливаю суть дискусии

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

Вот и я не улавливаю. С этого и начал ветку, что непонятно, что автор поста, на который я отвечал, хотел продемонстрировать своим кодом.

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

Т.е правильнее было бы написать так:

Так и хотел, но ошибся. Спасибо за исправление.

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