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

    • В сишке всё просто и понятно.
      Ответить
      • Ошибаешься. Вот в «PHP» всё действительно просто и понятно.
        Ответить
      • Ну это ж элементарно, можно сделать 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)];
        };


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

          А должны ли?)
          Ответить
          • Не должны. Запись в одно поле юниона, а чтение из другого - уб, вроде.
            Ответить
          • Это от стандарта зависит. Тут 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.
            Ответить
            • >Настоящие цари
              >каст структуры в структуру

              >>цари
              >>структуры

              Это несовместимые понятия.

              Повторюсь:
              Цари используют массивы, единственно полезную структуру данных.
              В массивах паддинга нет by design.
              Ответить
              • Почему цари против структур?
                Ответить
                • Потому что структура это высоуровневая хуйня, которая позволяет прокладке между CPU и креслом делать вид, что выравнивания не важны и получать пенальти или занимать дефицитное место в кеше.

                  Настоящие программисты используют массив, оптимизируя его под размер линейки кеша.
                  Ответить
                  • Если нужно итерироваться по строкам таблицы 10000000*5, то как лучше хранить таблицу с т.з. кеша, по строкам, или по столбцам? И почему? Кажется, я видел подобный вопрос в списке вопросов на собеседованиях.
                    Ответить
                    • Лучше всегда хранить всё последовательно, и так же обращаться.

                      Всё железо (от контроллера памяти до CPU) на это заточено.

                      Если ты считал байты 1,2,3 то байты 4,5,6 уже наверняка лежат в кеше.
                      Так что читать
                      1,2,3,4,5,6 всегда лучше, чем 1,42,100500.

                      Угадай теперь, как лучше читать
                      int petuh[100][200];
                      Ответить
                      • Так я к этому и вёл. Как же цари без структур?
                        Ответить
                        • не понял, зачем царям структуры?

                          ты просто храни себе массив, и теки.

                          ну вот доспустим есть у тебя структура из двух байт: на одном пики сохранены, а на другом сам знаешь что.

                          Так чем эта структура не char chairs[2] ?
                          Ответить
                          • Ну тогда какая замена структуры {int, char, double}?
                            Ответить
                            • Зависит от установленного у Царя компилятора, но пусть будет массив из 13 байт.

                              Царь может его и выровнять если того требует конкретная задача, но может и не выравнивать. Просто иногда скорость важнее, а иногда память, а иногда Царь знает, что у него будет N таких структур, где (13*N % [длина_кеша] == 0)
                              Ответить
                              • То есть чтобы попадать в кеш, царь будет хранить одномерный массив [10000000 * 13] байт и вручную кастить к трём типам?
                                Ответить
                                • Вообще, можете не отвечать. Зачем мне знать как какой-то там "Царь" делает, если это не общепринятая практика, или полезный спидхак?
                                  Ответить
                                  • Ололо, кого ебет что там практикуют питушки-неосиляторы, питушок?

                                    Царь делает оптимальный код, и питушки-неосиляторы могли бы тоже его писать, но увы: питушки-неосиляторы ничего не осилили кроме своих крестов, потому они и неосиляторы
                                    Ответить
                                    • Царь не осилил структуры
                                      Ответить
                                      • Конено питушок, а еще царь не осилил вижал бейсик, или на чем вы там пишете.

                                        Царю просто не нужны ненужные абстракции, а прокладкам между процессором и креслом очень нужны
                                        Ответить
                            • Структура per se Царю не нужна. Если она в количестве 1 (одной) штуки, то вместо неё можно использовать отдельные переменные. Если же у нас массив структур, то его можно заменить структурой массивов или... отдельными массивами.

                              Т. е. если у нас struct {int coq; char rooster; double xuroz;} petuh[100500]; то это можно заменить на int petuh_coq[100500]; char petuh_rooster[100500]; double petuh_xuroz[100500];

                              При итерации по таким массивам не будет ни дурацких паддингов, ни хромого шага.
                              Ответить
                              • Почему не будет хромого шага?
                                Ответить
                                • sizeof(char) != sizeof(double), поэтому если поместить их в один массив, Царю придётся его пробегать разными шагами либо дополнять чар мусором до размера дабла. А при итерации по массиву однотипных элементов шаг будет константой.

                                  Хотя возможно, я фигню написал, и это не имеет значения. Нужно смотреть конкретную задачу, чтобы понять, что и в каком порядке нам придётся доставать из массива.
                                  Ответить
                                  • >поэтому если поместить их в один массив, Царю придётся его пробегать разными шагами
                                    зачем?
                                    почему сразу смешение не посчитать?
                                    Ответить
                              • > При итерации по таким массивам не будет ни дурацких паддингов, ни хромого шага.

                                Только вот может быть всякая хуйня с кешмиссами
                                Ответить
                                • Действительно, если нужен доступ одновременно ко всем полям, то в моём варианте в кэш всё не влезет.
                                  Ответить
                      • Жаль, не могу найти ссылку на говнокод, в котором собрался консилиум на тему, в каком порядке обходить большую матрицу, чтобы оптимально использовать кэш.
                        Ответить
                        • P.S. Нашёл:
                          http://govnokod.ru/5286#comment69576
                          Ответить
                        • https://govnokod.ru/25171#comment444297 вот что-то нашел
                          Ответить
                          • Это немножко про другое, это про утаптывание неограниченного двухмерного массива в одномерный. Хотя тоже интересно. А кэш обсуждали в 5286.
                            Ответить
                            • Упомянутая там Z-order curve и Hilbert curve это тоже про кэш
                              Ответить
          • Можно еще такие структуры делать, чтоб там паддингов никаких нихуя не было, забить их своими паддингами, ну типа
            struct crap
            {
                uint8_t a;
                uint8_t padding1[7];
                uint64_t b;
                uint8_t c;
                uint8_t padding2[7];
                uint64_t d;
            };


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

              Цари используют массивы, единственно полезную структуру данных.
              Ответить
              • А массивы лежат плотно и у них нет паддингов.
                Ответить
                • Только если это не массивы структур.
                  Что там кстати стандарт говорит насчет выравниваний для базовых типов? Может ли быть ситуация, что 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. Какой багор!
                        Ответить
                        • Погоди, а разве нет такой хуйни, что если у тебя char* pituh = malloc(100), то нельзя сделать double* cock = (double*)(pituh + 1) ?
                          типа нужно выровнять по 4 байта
                          Ответить
                          • Да, так нельзя. Но если через 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)
                    Ответить
        • дада, я уже понял, что если явно память не очистить, то в падингах будет кал
          Ответить
          • То есть если предварительно сделать memset, то тогда ок? На это можно завязываться?
            Ответить
            • Я бы не был так уверен... Вдруг там какая-то ебанутая оптимизация, которая намеренно хуярит мусор в паддинги. Чтобы писать 3 байта одним dword'ом вместо трёх раз по байту, к примеру.
              Ответить
              • То есть если x и y — это структуры, x мы обнулили, а потом написали «x = y;», то эта операция присвоения может загадить паддинги, и их снова придётся чистить вилкой?
                Ответить
                • Мне кажется, что да.
                  Ответить
                  • Сиё сильно изгаживает первозданную изящность сишки.

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

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

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

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

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

                            Тарас же для игр использовал сугубо флоаты, потому прекрасно понимал что memcmp это кулцхакирство.
                            Ответить
                        • Хороший вопрос. Если сделать NaN == NaN, то все закукареают, и покажут на примере структуры из 1 поля какая сишка говно.
                          Ответить
                        • Зачем вообще сделали NaN != NaN?
                          Ответить
                          • Оно и не == и не !=. Оно тупо несравнимо. Вроде даже убить прогу за такое сравнение могут.
                            Ответить
                            • https://ideone.com/n09yzS
                              Ответить
                            • Убить за сравнение? А как тогда узнать, что в переменной NaN?
                              Ответить
                              • >А как тогда узнать, что в переменной NaN?
                                if (x!=x) { 
                                   printf("x is NaN!");
                                   console.log("x is NaN!");
                                }

                                Это кроссязыковое свойство между прочим.
                                Браузер от такого сравнения тоже почему-то не падает.
                                Ответить
                                • JS
                                  > NaN == NaN
                                  false

                                  ruby
                                  irb(main):002:0> (0.0/0) === (0.0/0)
                                  => false
                                  Ответить
                                  • А почему в «Ruby» тройной знак равенства? Там такая же проблема, как в «JS» и в «PHP»?

                                    Никак не могу запомнить, зачем этот знак нужен в «Ruby».
                                    Ответить
                                    • нет, тройное равенство тут вообще не к месту (я просто проебланил)

                                      нужно
                                      (0.0/0) == (0.0/0)

                                      но так тоже будет false.

                                      тройное равенство это проверка на принадлженость ренджу
                                      Ответить
                                • When we all give the power we all give the best!
                                  Ответить
                                • Кстати, гарантируется ли, что два произвольных NaNа будут побитово не равны?
                                  Ответить
                            • Нет.
                              Все операции сравнения с NaN возвращают false.
                              Кроме !=

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

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

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

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

                              Тем не менее, у типа real были значения -0 и +0, а сравнивать на равенство тоже приходилось через эпсилон.
                              Ответить
                              • Быстро отвечай, в каком языке тип real был типом по умолчанию у переменной, если явно его не указать?

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

                                  Шутку не знаю.
                                  Ответить
                                  • God is real.
                                    ...
                                    ...unless declared as integer
                                    Ответить
                                  • КАКОЙ БАГОР ))))))))))))))))))
                                    Ответить
                                    • да, зависимость типа переменной от имени это такая- венгерская нотация курильщика.
                                      Ответить
                                      • Эту фигню «Мокрософт» протащил в «Quick BASIC», но только в нём эти грабли сделали с телескопической ручкой: появилась директива DEFINT, в которой можно перечислить буквы, с которых должны начинаться целочисленные переменные. Фортрановским настройкам по умолчанию соответствовала директива DEFINT I-N.
                                        Ответить
                                        • а у меня был в децтве такой бейсик, у которого A$ это была строка, а A это число.

                                          был же такой?
                                          Ответить
                                          • А на coq ты не программировал?
                                            Ответить
                                          • Вообще если писать строго, то A% — это целое число, A! — плавающий питух, A$ — строка (в мокрософтовском бейсике ещё были A& и A# для целых и дробных чисел соответственно «двойной точности»).

                                            Если не указать знак типа, то может создаться целочисленная переменная (ну типа как в старой сишке, если не указать тип, то будет int).
                                            Ответить
                                            • ну вот, а вы еще над сигилами перловыми смеялись

                                              $imjaPetuha
                                              @petuhi
                                              %strukturaPituh
                                              PETUH_FILE_DESCIRPTOR
                                              Ответить
                                            • > 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 целых и плавающих питухов не различал.
                                            Ответить
                                            • Не заслуженно забыты qbasic, precomupter 1000 basic, а так же бейсики для spectrum и amiga и altair
                                              Ответить
                                              • 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 (@@)
                                                Ответить
                                                • >«Power BASIC» был сильно перегружен.
                                                  Не сильнее чем современные кресты и хаскели.
                                                  Ответить
                                                • # всю жизнь использовалась для номеров файлов в MS-ворециях бейсика.

                                                  Open FileName For Input as #1
                                                  Ответить
                                                  • Да, если она была перед цифрой.

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

                                              Да ты поехавший!
                                              Ответить
                              • Это как так? Я думал как плавающий питух процом поддержан, так и будет, независимо от языка.
                                Ответить
                                • CPU начиная с 486 имеют встроенный FPU и таким образом поддержаны процом, но ничто не мешает тебе реализовать свой флоат "програмно", правда?

                                  например, потому что ты царь, или хочешь поддержать 286 без копроцессора
                                  Ответить
                                  • Йоу, твое старое говно недостаточно старое говно. Это всё наследие не 486, а просто AS/400
                                    Ответить
                                • Процом поддержаны типы, совместимые с IEEE754. А бывают чисто софтварные типы.

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

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

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

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

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

                        https://projectlombok.org/features/EqualsAndHashCode
                        Ответить
                        • >Во-1. Для 100500 полей есть массивы. Нет, я серьёзно.
                          правда? ну-ка покажи-ка

                          >В жабамире уже давно никто ничего вручную не сравнивает,
                          ну-ну:)
                          http://www.javapractices.com/topic/TopicAction.do?Id=17

                          зы: в коко есть датаклассы, там это делается из коробки (Как у структур в C#)
                          Ответить
                          • Ну всё правильно.

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

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

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

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

                              Когда нету единого стандарта -- всё работает плохо.

                              Кто-то там планировал завезти в джаву структуры (шоб хранились на стеке и копировались), вероятно у них будет equals из коробки.
                              Ответить
                            • Расскажи про массивы-то.

                              Я знаю как один чувак юзал массивы чтобы представить массив структур чтобы избежать накладных расходов, но у них там были безумные требования совершенно к перформансу.
                              Ответить
                              • Если много однотипных данных: инты, чары то можно их распихать по разным массивам.
                                Если данные разнородные, то просто будет паддинг до интов.

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


                                Адресация идёт строго через енум, никаких магических цифр.
                                Ну и соответственно никто не мешает делать memcpy, memcmp и прочие царизмы.
                                Ответить
                                • В сишке есть много чего идематичного: и битмапы из интов, и серилазиция из коробки:) сишники -- люди ленивые, и писать километры бойлерплейта им лениво (в отличие от джавистов)
                                  Ответить
                                  • Разве их не перформанс в первую очередь интересует? Если нужен анролл - царь это сделает.
                                    Ответить
                                  • >битмапы из интов

                                    Ага. Вот это просто суперидиоматичная фича сишки.

                                    http://govnokod.ru/24276
                                    Ответить
                                    • А непрерывность массивов гарантируется как-то или тоже просто конвенция, которую могут в любой момент выкинуть на свалку истории ради пенальти перфоманса?
                                      Ответить
                                      • 6.1.2.5 Types

                                        "An array type describes a contiguously allocated nonempty set of objects"

                                        выдыхай, бабёр
                                        Ответить
                                        • Даже не знаю, это годный орднунг или огромный обсёр. ARM всё еще актуален да и память продолжает дешеветь.
                                          Ответить
        • Так Царь же мудро пояснял нубам, что структуры нинужны.

          А у массивов паддинга нет by design.
          Ответить
      • В паддингах может лежать мусор.
        Ответить
        • лол) спасибо, если у меня структа на стеке или на куче, но я забыл явно памятьв ынулить, то да
          Ответить
          • Да даже если занулил, скорее всего. Unspecified такой unspecified.
            Ответить
    • Я только не понял предложение про -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
      Ответить
      • Я за «Бормандосток».
        https://gcode.space/ngk/#!/search?user=TheCalligrapher
        Ответить
        • Зачем ты отвечаешь уебку?
          Ответить
          • Уёбок, пи не уёбок
            Уёбок тут стертор
            Ответить
            • ^ this.
              Ответить
            • Нет, он уебок, срущий ворециями.
              Ответить
              • Вореции нужны, вореции важны.
                Ответить
                • Я тоже согласен с тобой. Вореции важны для обсуждения отношений между болтами и другими людьми. Жизнь так и не посмотрел тот урок в интернете на шампунь доя усов из швейцарии с помощью кисточек решил пересеч. В общем помучался с этим отчетом целый день и я не пойду дальше в школу потому не хочу в гробу сидеть.
                  Ответить
                  • Когда я несу бред, я выношу его горячим, с ягодами и тюленями, которые танцуют самбо с совой, которая пытается заварить полный чайник гречки, но ничего не получается, потому что с таким характером трудно подобрать обои для спальни.
                    Ответить

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