1. Си / Говнокод #26034

    +2

    1. 1
    2. 2
    Comparing structs with, let's say, memcmp, does not work,
     as you end up comparing the "unspecified" padding bytes as well — you must compare member-by-member.

    While writing this post, the author observed that some verions of GCC (experimentally, >= 4.7, < 8.0) do not zero padding if an empty intializer list is passed, under certain a certain code pattern; if an entire struct (i.e. sizeof(STRUCTNAME)) is subsequently memcpy'd after assigment of its members, and this intermediate buffer is what is used by the code going forward. This appears to be based on how optimization passes interact with GCC's built-in memcpy, since passing -fno-builtin-memcpy returns the behavior to the expected.
    https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2019/october/padding-the-struct-how-a-compiler-optimization-can-disclose-stack-memory/

    Запостил: 3.14159265, 18 Ноября 2019

    Комментарии (179) RSS

    • В сишке всё просто и понятно.
      Ответить
      • показать все, что скрытоvanished
        Ответить
      • Ну это ж элементарно, можно сделать union:
        struct crap
        {
            uint8_t a;
            uint64_t b;
            uint8_t c;
            uint64_t d;
        };
        
        union crap_union
        {
          struct crap crapstruct;
          uint8_t craparr[sizeof(struct crap)];
        };


        И инициализировать через этот говномассив нулями. Тогда там все эти говнопаддинги занулиться должны
        Ответить
        • > должны

          А должны ли?)
          Ответить
          • показать все, что скрытоvanished
            Ответить
          • Это от стандарта зависит. Тут https://stackoverflow.com/q/11639947 можешь глянуть.

            На всякий случай, в GCC предусмотрена особая хуйня __attribute__ ((may_alias))
            #include <stdio.h>
            #include <inttypes.h>
            #include <string.h>
            
            struct crap_may_alias
            {
                uint8_t a;
                uint64_t b;
                uint8_t c;
                uint64_t d;
            } __attribute__((__may_alias__));
            
            
            struct crap
            {
                uint8_t a;
                uint64_t b;
                uint8_t c;
                uint64_t d;
            };
            
            int main() 
            {
              uint8_t arr[sizeof(struct crap)] = {0};
              struct crap_may_alias *crap_mayalias_ptr = (struct crap_may_alias *)arr;
              struct crap regular_crap;
              memcpy(&regular_crap, crap_mayalias_ptr, sizeof(struct crap));
              return 0; 
            }

            Видишь как всё просто
            Ответить
        • Так проблема не в инициализации (memset наше всё!)

          Проблема в том что когда мы начнём писать в поля значения, компилеру ничего не помешает опять засрать паддинги ворециями.

          Допустим мы пишем uint8_t а и uint8_t с. А компилер джва присваивания оптимизирует в один mov с мусором в паддинге.

          Ниже по треду bormand уже пояснял.
          Ответить
          • И ещё не факт что он memset через union не разъебёт на заполнение каждого поля по отдельности... Если заметит, что craparr никому нахуй не нужен потом.
            Ответить
          • Настоящие цари напишут макрос, который паддинги занулит через каст структуры в структуру с uint8_t arr[sizeof(struct crap)] и __attribute__((__may_alias__))

            Не, ну ясен хер что это говно и костыли, в крестах кстати type punning через union это вообще UB.
            Ответить
          • Можно еще такие структуры делать, чтоб там паддингов никаких нихуя не было, забить их своими паддингами, ну типа
            struct crap
            {
                uint8_t a;
                uint8_t padding1[7];
                uint64_t b;
                uint8_t c;
                uint8_t padding2[7];
                uint64_t d;
            };


            И тогда проблем нет. Осталось изобрести метушню на крестоговне, которая эти паддинги нагенерирует.
            Ответить
            • Кстати почему в крестоговне до сих пор нет такой фичи, чтоб типа указать некоторой компилтайм-метушне что вот такая-то структура, и ты мне сделай новое определение структуры на основе этой, добавив/убрав/изменив вот такое-то говно? Только какое-то говнонаследование есть.
              Ответить
              • показать все, что скрытоvanished
                Ответить
              • Это уже компайл-тайм рефлексия получается. Её крестухи с прошлого века ждут.
                Ответить
                • Почему в кресты подобавляли кучу другой хуйни, вроде лямбд, констэкспров и всяких там std::embed, а конкретно вот эту хуйню добавить не могут?
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                  • Сложна, наверное. Для лямбд, констэкспров и прочей поебени особенно сильно ничего менять не надо (лямбда —сахарок над структуркой, констэкспр — одно ключевое слово и кучка правил, std::embed — просто одна функция). А вот для рефлексии надо будет вводить целую систему метатипов и дохуя обвязки для них: контейнеры, алгоритмы, раздел про типы придётся вообще чуть ли не заново писать… И ладно бы просто можно было написать: «надо сделать std::kakaja_to_hujnja(Hujnya hujnja)», а с реализацией пусть разрабы конпеляторов ебутся. Но увы, для рефлексии придётся половину Стандарта перелопачивать, а заниматься этим никто не хочет (рискну предположить, что и не может).
                    Ответить
    • показать все, что скрытоvanished
      Ответить
      • Паддинг одинаковый по размеру, но он может быть забит мусором. Поэтому при сравнении структур нужно сравнивать поля по отдельности, а не по-царски через memcmp сравнивать весь блок памяти.
        Ответить
        • показать все, что скрытоvanished
          Ответить
          • Цари обколются своей арифметикой указателей, а потом читают шум океанов планеты Марс вместо полезных данных.
            Ответить
            • Структуры юзают только заедушные анскилябры.

              Цари используют массивы, единственно полезную структуру данных.
              Ответить
              • А массивы лежат плотно и у них нет паддингов.
                Ответить
                • Только если это не массивы структур.
                  Что там кстати стандарт говорит насчет выравниваний для базовых типов? Может ли быть ситуация, что int у нас 5-байтный, но требование к выравниванию у него 2 байт, и тогда с массивом получится хуита вида
                  | 0  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
                  |byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|byte|
                  |           int          | -- |           int          | -- |           int          | -- |

                  ?
                  Тогда и без структур будут паддинги
                  Ответить
                  • > массивы структур

                    Дык там паддинги будут в самих структурах, а не между элементами массива...

                    > int 5-байтный

                    Х.з., конкретной формулировки не нашёл. Но там написано, что int'ы могут содержать padding биты. Т.е. скорее всего твоё выравнивание на 2 байта будет встроено внутрь самого int'а. Но это не точно.
                    Ответить
                    • Некоторые реализации 80-битный тип long double выравнивают до 96 битов (12 байтов) или до 128 битов (16 байтов). Выравнивание встраивается в само значение, а не снаружи.
                      Ответить
                      • Тогда ведь получается, что если царь захочет массив из 80-битных long double без проебов байтиков на выравнивание, ему придется делать массив из char и вгружать-выгружать туда значения через memcpy. Какой багор!
                        Ответить
                        • показать все, что скрытоvanished
                          Ответить
                          • Да, так нельзя. Но если через memcpy читать-писать, тогда норм

                            Типа
                            char* pituh = malloc(100); double cock; memcpy(&cock, pituh + 1, sizeof(cock));
                            Ответить
                            • Кстати, если надо хранить много флоатов, но при этом нам известно что все флоаты положительны, можно позапихивать мантиссу и экспоненту без знакового бита, и потом руками побитово выковыривать флоаты, и на каждом флоате экономить целый бит. И если например известно, что экспонента будет в таких-то пределах - тоже что-то наэкономить можно.

                              Интересно, такая хуйня где-нибудь используется?
                              Ответить
                              • Экспонента в IEEE 754 и так хранится без знакового бита. Она хранится со смещением. Например, у дабла диапазон экспоненты -1023..+1022, а хранится она как число в диапазоне 0..2047. Чтобы получить настоящую экспоненту, из того, что хранится, нужно вычесть 1023.
                                Ответить
                                • Ты помнишь наизусть все IEEE от 1 до 754?
                                  Ответить
                                • > Экспонента в IEEE 754 и так хранится без знакового бита.

                                  А где я такое заявлял? Мантисса отдельно, экспонента отдельно, знаковый битик отдельно. http://www.softelectro.ru/ieee754.html

                                  Поэтому кстати в плавучих 754-х питухах есть отрицательный и положительный ноль, в отличии от знаковых целочисленных питухов в дополнительном коде(two’s complement), где такой хуйни нет.

                                  А вот беззнаковых плавучих 754-х питухов не завезли к сожалению, поэтому на каждого такого питуха будет тратиться целый лишний бит
                                  Ответить
                                  • Посмотрим, сколько можно сэкономить от одного бита:
                                    1/32 = 3,125%
                                    1/64 = 1,5625%
                                    1/80 = 1,25%

                                    Так себе экономия. Зато потеря пирфоманса от упаковки/распаковки. Разве что для архивного формата пойдёт.

                                    У меня другое предложение: добавить этот бит к мантиссе либо к порядку, чтобы расширить точность или диапазон. У целых чисел этот бит как раз расширяет верхнюю границу. Да, получится плавающий питух, не полностью совместимый с IEEE 754.
                                    Ответить
                        • > 80-битных long double
                          Это же отрыжка 8087, на нормальных платформах старым говном не пользуются, там есть нативная поддержка banaly64
                          Ответить
                  • Скорее всего может.
                    Выравнивание должно быть степенью двойки:
                    Alignments are represented as values of the type std::size_t.
                    Valid alignments include only those values returned by an alignof
                    expression for the fundamental types plus an additional
                    implementation-defined set of values, which may be empty.
                    Every alignment value shall be a non-negative integral power of two.
                    (§6.11/4)

                    У char'ов оно должно быть самым маленьким:
                    Alignments have an order from weaker to stronger or stricter
                    alignments. Stricter alignments have larger alignment values.
                    An address that satisfies an alignment requirement also satisfies
                    any weaker valid alignment requirement.
                    
                    The alignment requirement of a complete type can be queried
                    using an alignof expression (8.3.6). Furthermore, the narrow
                    character types (6.9.1) shall have the weakest alignment
                    requirement. [ Note: This enables the narrow character types
                    to be used as the underlying type for an aligned memory area
                    (10.6.2).—end note ]
                    (§6.11/5,6)

                    А вот про выравнивание остальных фундаментальных типов я не нашёл ничего, кроме намёка на то, что оно есть:
                    For each of the standard signed integer types, there exists
                    a corresponding (but different) standard unsigned integer type:
                    “unsigned char”, “unsigned short int”, “unsigned int”, “unsigned long int”,
                    and “unsigned long long int”, each of which occupies the same
                    amount of storage and has the same alignment requirements (6.11)
                    as the corresponding signed integer type48; that is, each signed
                    integer type has the same object representation as its corresponding
                    unsigned integer type.
                    (§6.9.1/3)
                    Ответить
        • показать все, что скрытоvanished
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • Я бы не был так уверен... Вдруг там какая-то ебанутая оптимизация, которая намеренно хуярит мусор в паддинги. Чтобы писать 3 байта одним dword'ом вместо трёх раз по байту, к примеру.
              Ответить
              • То есть если x и y — это структуры, x мы обнулили, а потом написали «x = y;», то эта операция присвоения может загадить паддинги, и их снова придётся чистить вилкой?
                Ответить
                • Мне кажется, что да.
                  Ответить
                  • Сиё сильно изгаживает первозданную изящность сишки.

                    Превращает простейшие вещи в унылое оопешное шарпожабство с необходимостью писать ручные equalsы на каждое поле, сеттеры и копирующие конструкторы.
                    Ответить
                    • Да не говори, засрали своими UB'ами весь язык.
                      Ответить
                    • показать все, что скрытоvanished
                      Ответить
                      • Интересно что будет когда в структуре сидят плавающие питухи, съевшие перед сравнением NaN.
                        Ответить
                        • Компилятор мог бы и сам догадаться, что делать в этом случае!
                          Ответить
                          • Он и догадается.

                            Выберёт из джвух вариантов:
                            1) NaN == NaN //always false
                            2) UB
                            Ответить
                        • А серьёзно, как сравнивать структуры с плавающими питухами? Если сравнивать через memcmp или типа того, то они будут равны, если NaN'ы одинаковые (у NaN есть хвост, заполненный произвольными битами). Если же сравнивать по стандарту IEEE, то NaN не равен любому NaN (даже самому себе).
                          Ответить
                          • >А серьёзно, как сравнивать структуры с плавающими питухами?

                            Ручками писать сравнения каждого поля.

                            А флоаты никто не сравнивает через ==. Это делают через эпсилон, как учили в школе.

                            C опциональной обработкой NaNа согласно логике кода.

                            Тарас же для игр использовал сугубо флоаты, потому прекрасно понимал что memcmp это кулцхакирство.
                            Ответить
                        • показать все, что скрытоvanished
                          Ответить
                        • показать все, что скрытоvanished
                          Ответить
                          • Оно и не == и не !=. Оно тупо несравнимо. Вроде даже убить прогу за такое сравнение могут.
                            Ответить
                            • показать все, что скрытоvanished
                              Ответить
                            • Убить за сравнение? А как тогда узнать, что в переменной NaN?
                              Ответить
                            • Нет.
                              Все операции сравнения с NaN возвращают false.
                              Кроме !=

                              Это записано не в сишном стандарте, а стандарте для флоатов: IEEE 754.

                              Потому оно по идее должно быть однородно во всех языках.
                              Ответить
                            • Можно еще вспомнить что значения -0. и 0. будут равны при сравнении через == но не равны при сравнении через memcmp
                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                                  • В каких-то бейсиках можно было так сравнивать. Там рантайм плавающих питухов сравнивал не точно, а с некоторым допуском, чтобы их можно было использовать вместо целых без переделки кода. Как мы уже выяснили, в синклеровском «Бейсике» (на «Спектруме») и на «Atari» целые и плавающие питухи не различались, поэтому там это было необходимостью.

                                    А в остальных языках сравнивать плавающих питухов на точное равенство нельзя. Даже в «PHP».
                                    Ответить
                          • >Зачем вообще сделали NaN != NaN?

                            «Патамучто это плавающий питух, который априори говно. И чем вы быстрее это поймёте, чем будет лучше.» ⓒ
                            http://govnokod.ru/13189#comment182595
                            Ответить
                            • А в «Турбо Паскале» был тип real, несовместимый с IEEE754. Этот тип не поддерживал inf и NaN, а также denormalized (underflow). При делении на ноль там тупо выскакивала ошибка, как у целого питуха.

                              Тем не менее, у типа real были значения -0 и +0, а сравнивать на равенство тоже приходилось через эпсилон.
                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • В «Фортране». Однако, если переменная начиналась с букв I, J, K, L, M, N, то у неё тип по умолчанию мог быть целым питухом.

                                  Шутку не знаю.
                                  Ответить
                                  • показать все, что скрытоvanished
                                    Ответить
                                  • показать все, что скрытоvanished
                                    Ответить
                                    • показать все, что скрытоvanished
                                      Ответить
                                      • Эту фигню «Мокрософт» протащил в «Quick BASIC», но только в нём эти грабли сделали с телескопической ручкой: появилась директива DEFINT, в которой можно перечислить буквы, с которых должны начинаться целочисленные переменные. Фортрановским настройкам по умолчанию соответствовала директива DEFINT I-N.
                                        Ответить
                                        • показать все, что скрытоvanished
                                          Ответить
                                          • показать все, что скрытоvanished
                                            Ответить
                                          • Вообще если писать строго, то A% — это целое число, A! — плавающий питух, A$ — строка (в мокрософтовском бейсике ещё были A& и A# для целых и дробных чисел соответственно «двойной точности»).

                                            Если не указать знак типа, то может создаться целочисленная переменная (ну типа как в старой сишке, если не указать тип, то будет int).
                                            Ответить
                                            • показать все, что скрытоvanished
                                              Ответить
                                            • > A% — это целое число, A! — плавающий питух, A$ — строка

                                              Не. Этот новодел уже в QB завезли.
                                              В олдбейсике, том что с метками, такое не работало. Только значок доллара для строк.
                                              Ответить
                                              • Ещё в каких-то бейсиках было. A& и A# — точно новодел, он за пределами QB нигде не встречался. А вот A% и A! были где-то ещё, но я сходу не вспомню, где.
                                                Ответить
                                                • Там же ещё такой прикол был, что функции возвращающие строки оканчивались долларом.
                                                  MID$, LEFT$
                                                  А других суффиксов я не припоминаю.

                                                  Я кажется экспериментировал с другими значками (документации ведь не было), вроде они все падали с ошибкой.
                                                  Может какой-то другой, более поздний диалект. Но кроме QB я больше такого нигде не видел.
                                                  Ответить
                                          • >бейсик, у которого A$ это была строка, а A это число.
                                            >был же такой?

                                            Был. И не у одного тебя.
                                            Ответить
                                          • У меня в детстве была книжка, где буржуйские доллары были заменены - нет, не на кружок с шипами (не знаю, как он называется), а на полужирную S. Такой багор был, когда я с книжки программу списываю (там же еще диалект другой), что-то типа DATA "Hello!": READ AS а он мне пишет какое-то C Nonsense in BASIC ыыыыы
                                            Ответить
                                        • >Эту фигню «Мокрософт» протащил в «Quick BASIC»

                                          Бейсик (ещё до мелкомягких) во многом вырос именно из фортрана.

                                          Строки-метки, операторы типа IF X THEN a где a — номер метки; динамическая типизация, пресловутый god is real.

                                          Причём, если в фортране были целые, то в бейсике не стали заморачиваться, и сделали всё даблами. Впоследствии js заимствовал эту парадигму.

                                          ANDы и ORы по каким-то хитрым, неявным правилам конвертились в целые. Прям как в яваскрипте.

                                          We made no distinction between floating-point arithmetic; we used only double precision floating-point internally, and adopted several strategies to make loop termination come out right.
                                          Ответить
                                          • Ах да. И бейсиковский оператор DIM для переменных-массивов, тоже навеян фортраном:
                                            DIMENSION ARR(3,4)
                                            DIM ARR(3,4)
                                            Ответить
                                          • «Кубейсик» ещё кое-что утащил из «Фортрана». Например, блок архаичный COMMON (по факту его никто не использовал).

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

                                            В «Кубейсике», как я уже заметил, целые и вещественные различались явно. Для переменных использовались разные суффиксы (%, !, &, #) либо директивы DEFINT/DEFSNG/DEFLNG/DEFDBL (для любителей венгерки) либо спецификаторы в выражении DIM (DIM AS INTEGER, DIM AS SINGLE, DIM AS LONG, DIM AS DOUBLE).

                                            Целые и вещественные были ещё где-то разделены, помимо «Кубейсика». Я уже отметил суффиксы % и !, но точно не вспомню, в каких реализациях они поддерживались. Придётся перебирать.

                                            В реализациях, которыми я пользовался, AND и OR можно было использовать только в выражении IF. То есть булев тип ни во что не кастовался и даже сохранить его в переменной было нельзя. Вот так булев тип был ущемлён в правах.
                                            Ответить
                                          • Поехали проверять.

                                            Applesoft BASIC: был суффикс % для целого питуха; булев тип кастовался в целые.
                                            http://wiki.apple2.org/index.php?title=Applesoft_BASIC_Ref#Nume ric_Expressions_and_Assignments:

                                            GW-BASIC: четыре типа числовых переменных, как в «Кубасике».
                                            https://hwiegman.home.xs4all.nl/gw-man/index.html

                                            BBC BASIC: есть суффикс % для целого питуха.
                                            http://www.bbcbasic.co.uk/wiki/doku.php?id=number_20conversion_20in_20b asic

                                            Вильнюсский Бейсик (БК-0010): три типа числовых переменных (суффикс % для целых и суффиксы ! и # для двух типов плавающих питухов).
                                            http://www.emuverse.ru/wiki/УКНЦ_Бейсик_Описание_языка

                                            Вот Sinclair Basic целых и плавающих питухов не различал.
                                            Ответить
                                            • показать все, что скрытоvanished
                                              Ответить
                                              • rom basic еще вспомни
                                                Ответить
                                              • >> qbasic

                                                Это и есть «Quick Basic», который я упоминал раньше.

                                                >> бейсики для spectrum

                                                Это «Sinclair BASIC».

                                                Остальные нужно проверить, да.
                                                Ответить
                                              • «Atari BASIC» не различал целых и плавающих питухов.
                                                https://www.atariarchives.org/basic/showpage.php?page=53

                                                «Commodore BASIC»: был суффикс % для целых, в противном случае питух считался плавающим. Булев тип кастовался в целый.
                                                http://www.zimmers.net/cbmpics/cbm/c65/c65manual.txt

                                                В «UBASIC» был суффикс % для «маленьких» чисел (они назывались short variables; занимали одно машинное слово) и # для «больших» чисел (они назывались extra variables; могли вместить до 540 машинных слов). Причём одна и та же переменная могла хранить целое число, рациональное, вещественное, комплексное или многочлен. Да, различались рациональные и вещественные, а так же в переменной можно было хранить многочлен одной переменной (лямбды в Бейсике, ужас).
                                                ftp://ftp.bu.edu/mirrors/simtelnet/msdos/ubasic/


                                                В документации по «Amiga BASIC» нашёл суффиксы %, !, # на 197-й странице:
                                                OPEN "AccountInfo" AS #2 LEN = 14
                                                FIELD #2,8 AS ACCT$,4 AS CHECK$,2 AS DEPOSITS
                                                LET ACCOUNTNO# = 9876543325560
                                                LET CHECKING! = 123456!
                                                LET SAVINGS% = 2500
                                                LSET ACCT$ = MKD$(ACC0UNTN0#)
                                                LSET CHECKS = MKS$(CHECKING!)
                                                LSET DEPOSITS = MKI$(SAVINGS%)
                                                PUT #2,1
                                                CLOSE #2
                                                END

                                                https://archive.org/download/AmigaBasic

                                                «Power BASIC» был сильно перегружен. Для числовых переменных была куча суффиксов:
                                                Byte (?)
                                                Word (??)
                                                Integers (%)
                                                Double-word (???)
                                                Long integers (&)
                                                Quad integers (&&)
                                                Single-precision floating-point (!)
                                                Double-precision floating-point (#)
                                                Extended-precision floating-point (##)
                                                Currency (@)
                                                Extended-currency (@@)
                                                Ответить
                                            • показать все, что скрытоvanished
                                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                                  • Йоу, твое старое говно недостаточно старое говно. Это всё наследие не 486, а просто AS/400
                                    Ответить
                                • Процом поддержаны типы, совместимые с IEEE754. А бывают чисто софтварные типы.

                                  У «Бейсика» тоже были свои типы плавающих питухов. Гугли MBF (Microsoft binary format).
                                  Ответить
                                  • показать все, что скрытоvanished
                                    Ответить
                                    • Да, у него был чисто софтварный тип real плюс софтварный эмулятор типов IEEE754 (включая 80-битный промежуточный, который в нём звался extended, а в распространённых реализациях сишки зовётся long double).

                                      Операции с типами IEEE754 переключались на хардварные, если процессор их поддерживал (модуль SYSTEM проверял это при старте программы), а вот операции с типом real всегда оставались софтварными, потому что ни один проц такой царский тип не поддерживал.
                                      Ответить
                                      • вот чорт
                                        макака думала, что real это у них был double

                                        Кстати, о разницах между реализациями питуха
                                        Знаешь такой бугор
                                        https://en.wikipedia.org/wiki/Strictfp
                                        ?
                                        Ответить
                                        • Real действительно эквивалентен double в некоторых реализациях «Паскаля», но только не в «Турбо Паскале» и в его наследниках («Delphi», «FPC» etc.). В TP и в его наследниках это разные типы.

                                          Про strictfp что-то слышал, но пока не копал этот вопрос.
                                          Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                    • При этом ещё в древнем «Фортране» чуть ли не во все функции можно было подставлять массивы вместо скаляров. Умный компилятор сам разбирался, что с этим делать.
                      Ответить
                    • показать все, что скрытоvanished
                      Ответить
                      • >вручную сравнивать 100500 полей, как в жабе

                        Во-1. Для 100500 полей есть массивы. Нет, я серьёзно.
                        Во-2. В жабамире уже давно никто ничего вручную не сравнивает, @lombok.EqualsAndHashCode

                        https://projectlombok.org/features/EqualsAndHashCode
                        Ответить
                        • показать все, что скрытоvanished
                          Ответить
                          • Ну всё правильно.

                            Там два десятка правил, как правильно сравнивать. И парочка исключений из этих правил.

                            Список pitfalls по твоей ссылке достойный, но там есть ещё парочка: типа невозможности найти объект с мутабельными полями в хеш-мапе, плюс те же флоаты.

                            Блох вопросу equals посвятил треть своей книжки.

                            Потому никто их руками обычно не пишет, а либо генерируют через IDE, либо @lombok.EqualsAndHashCode.
                            Ответить
                            • показать все, что скрытоvanished
                              Ответить
                            • показать все, что скрытоvanished
                              Ответить
                              • Если много однотипных данных: инты, чары то можно их распихать по разным массивам.
                                Если данные разнородные, то просто будет паддинг до интов.

                                В сишке есть дико идиоматичная инициализация массивов, подобная структурам.
                                И в сишке есть енумы c опциональной автонумерацией.
                                //Сначала заводим константы-сдвиги
                                enum fields {
                                  FIELD1,
                                  FIELD2,
                                  FIELD3=4,
                                }
                                //потом инициализируем массив
                                
                                char *const map[] = {
                                    [FIELD1]          = "this",
                                    [FIELD3]         = "and this"
                                };


                                Адресация идёт строго через енум, никаких магических цифр.
                                Ну и соответственно никто не мешает делать memcpy, memcmp и прочие царизмы.
                                Ответить
        • Так Царь же мудро пояснял нубам, что структуры нинужны.

          А у массивов паддинга нет by design.
          Ответить
      • В паддингах может лежать мусор.
        Ответить
    • Я только не понял предложение про -fno-builtin-memcpy. Что меняется от этого параметра?
      Ответить
      • https://godbolt.org/z/V7xrRD
        https://godbolt.org/z/dPHBkb


        Мусор зануляется.

        Добавь -fno-builtin-memcpy и тогда из паддингов пропадёт мусор: 7F 05 05
        Ответить
    • Всё-таки профитная идея — взять посты TheCalligrapher, разбить по темам и напечатать отдельной книжечкой: «Как делать поменьше хуйни в Сишке и Крестах».

      http://govnokod.ru/9686#comment132740
      Ответить

    Добавить комментарий