- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
// https://git.zx2c4.com/BruteZip/tree/read.c?id=e4e9c17b99e0d108136b8a07632b1ebaa7d09d28#n26
int main(int argc, char *argv[])
{
union {
long int l;
char c[sizeof(long int)];
} u;
u.l = 1;
if (u.c[sizeof(long int) - 1] == 1) {
printf("This program only runs on little endian archs, because I'm lazy. Sorry.\n");
return -2;
}
Перемешивание байтов из-за «big engian», «little endian», «middle endian» меня не интересует, это и так понятно.
Коверкание чисел из-за копирования целого питуха в плавающего и обратно меня тоже не интересует. Видел я алгоритм с «обратным квадратным корнем» (0x5F3759DF), меня этим не запугать.
Что ещё бывает?
нахуй такой юнон, я всегда считал, что это чтоб память экономить для данных, которые не юзаются одновременно, и чтоб юзать как reinterpret_cast в крестах.
Сравни:
И вот этот ужас:
Вот тут, например, и не «посмотреть по-другому» (reinterpret_cast), и не «расширение/сужение», тут полноценное преобразование (с кучей арифметических действий).
Я считаю, что (int) не нужен. Лучше явно использовать floor/ceil/round/что-то там ещё, чтобы показать, как именно ты хочешь округлить.
Теоретически компилятор или рантайм могли проверить текущее значение дискриминанта (what в нашем примере), чтобы разрешить доступ только к одному варианту.
Компания «Борланд» при реализации своего диалекта решила на дискриминант положить болт. В «Турбо Паскале» и в его наследниках можно в любой момент использовать любой вариант (как в «сишке» можно использовать любой член союза):
И в «Турбо Паскале» уже можно записать значение в petookh.age, а прочитать из petookh.iq, хотя «Standard Pascal» этого не позволял.
Стандарт я этим не нарушу?
00101010
01010100
10101000
01010001
10100010
01000101
10001010
00010101
Он не потребует лишней памяти.
Всегда 42.
http://eel.is/c++draft/class.union (в других стандартах примерно то же самое)
> If a standard-layout union contains several standard-layout structs that share a
> common initial sequence ([class.mem]), and if a non-static data member of an
> object of this standard-layout union type is active and is one of the standard-layout
> structs, it is permitted to inspect the common initial sequence of any of the
> standard-layout struct members
У тебя в юнионе оба члена одинакового типа и они полностью занимают common
initial sequence. Это то же самое, что сделать мемсру из одного в другого.
> поясни тогда цытаткуо
UPD: бля, чёт я не посмотрел на то, что тут всё про си, но чует мой пушистый зад, что в си всё намного проще, ибо нет классов и связанного нетривиального говна
Выравнивание полей структуры он разрешает, поэтому при описании структур приходится вставлять директивы компилятора (#pragma, __attribute__), чтобы не выравнивал. У некоторых ЯП даже было слово «packed» для этого.
Нет. Возьми юнион из uint64_t и uint8_t[9]. Его размер будет 16 а не 9.
Да. Поэтому по-дефолту размеры всех типов достаточно выровнены.
i8,i16,i32,i64,i128
u8,u16,u32,u64,u128
isize,
usize
и никакой питушни с этими вашими sizeof
На DSP, где один октет адресовать нельзя в принципе. У них в «байте» может быть 16, 32 или даже 64 бита, чего вполне хватает для того, чтобы вместить целый long int.
Были ещё древние процессоры с 24-битными, 32-битными, 36-битными, 48-битными словами, не разбитыми на байты. У «PDP-10» известный компилятор «Си» разбивал 36-битное слово на 9-битные «байты» (нонеты), но другие компиляторы могли и не разбивать.
char бывает разным. Он не обязан быть восьмибитным. Точно так же long int не обязан вмещать несколько чаров.
Тебе другой гость написал нестрогое неравенство, из которого следует, что long int может совпасть с чаром.
Были какие-то реализации, авторы которых поняли слово «char» буквально и решили уместить в него юникодный символ.
Ещё у IEEE754 есть инструкции для двоично-десятичных данных.
А у IBM/370 был шестнадцатеричный плавающий питух:
https://en.wikipedia.org/wiki/IBM_hexadecimal_floating_point
Там порядок означал не на сколько битов нужно сдвинуть мантиссу, а на сколько шестнадцатеричных цифр.
Умею я считать до двух!
—– Подумаешь! –— ворчит хорёк. —–
А я могу до четырёх!
–— Я —– до шести! –— воскликнул жук.
—– Я –— до восьми! —– шепнул паук.
Тут подползла сороконожка:
–— Я, кажется, умней немножко
Жука и даже паука —–
Считаю я до сорока!
—– Ах, ужас! –— ужаснулся уж. —–
Ведь я ж не глуп. Но почему ж
Нет у меня ни рук, ни ног,
А то и я считать бы мог!
А у меня есть карандаш.
Ему что хочешь, то задашь.
Одной ногой умножит, сложит.
Всё в мире сосчитать он может!
Допустим, я заюзал юникодные смайлики в строковых литералах. В чар они не входят. ЧЯНТД?
§ 4.4, 1
§ 5.3, 1
5.2.1.2 Multibyte characters
The basic character set shall be present and each character shall be encoded as a single byte.
Т.е. таки минимум 7 бит независимо от кодировок.
§ 6.9.1, 7
§ 6.9.1, 7, сноска 52.
Ну и bit - unit of data storage in the execution environment large enough to hold an object that may have one of two values.
По такой логике на 64-битной машине надо было вообще делать sizeof(int) == 8.
Но ведь при сохранении данных в файл или при отправке по сети использовался явный размер. Допустим, у меня есть формат графического файла с плотностью 24 бита на пиксель (каналы R, G, B по 8 бит). Если я вместо 24 битов запишу 16, 32 или 64, аргументируя это тем, что такой размер инта на моей машине, то этот файл никто не сможет прочитать (точнее, смогут только те, кто компилировал вьюер тем же компилятором). Значит, мне придётся использовать низкоуровневую питушню, в которой я могу размер указать явно.
Почему они так сделали?
Так вот, «II» означает «Иинтел», т. е. числа, не помещающиеся в байт, записывали адепты маленького конца.
«MM» означает «Ммоторола», т. е. числа, не помещающиеся в байт, записывали адепты большого конца.
Естественно, как на машине с «little endian», так и на машине с «big endian» можно было посмотреть порнокартинки обоих форматов, просто при просмотре файлов с сигнатурой «MM» на машине с интеловским процессором теоретически чуть-чуть снижался пирфоманс из-за необходимости менять порядок байтов. Хотя какой к чёрту пирфоманс из-за порядка байтов, когда основное время съедает ввод-вывод или разжатие?
Т.е. тебе вообще похуй на результат твоей проги?
Есть 3 стула:
1) Для корректной работы проги тип должен вместить нужные мне числа. И мне похуй, как конпелятор его реализует.
2) Для корректной работы проги тип должен иметь указанные мной размер и представление.
3) Мне нужен самый эффективный тип на данной платформе (для длинной арифметики, к примеру).
int описывает только третий вариант. А этот вариант в реальном коде встречается гораздо реже первого...
З.Ы. Разрабатывая код, я вообще не знаю что я могу засунуть в int т.к. минимальный размер инта описан в informative приложении к стандарту, которое никого ни к чему не обязывает.
Ну я же пишу - во время разработки кода, а не во время копуляции.
Т.е. язык оказался настолько непригоден для разработки, что почти сразу (лет через 8) пришлось к нему нагородить внешний конфигуратор из говна и палок. Ок.
Это одно из следствий похуизма.
Не, с файлами другая история. Никто не верил, что появятся настолько огромные накопители и тем более файлы. Причём много раз подряд не верили. Да и сейчас не верят - диски перевели на унылое LBA48 вместо LBA64.
Эдак и многозадачность можно запилить.
Иди второй вариант дочитай, блджад.
> int описывает только третий вариант.
Нет, не описывает. На x86-64 у тебя будет 32-битный int, но для эффективной длинной арифметике на данной платформе лучше взять 64-битный тип
Нет, это не в informative. Ну может в каких-то старых и так, но давай взглянем на C17 :
> 6.2.5 Types
> A "plain" int object has the natural size suggested by the architecture of the executionenvironment (large enough to contain any value in the range INT_MIN to INT_MAX as defined in the header <limits.h>).
> 5.2.4.2.1 Sizes of integer types <limits.h>
> Moreover, except for CHAR_BIT and MB_LEN_MAX, the following shall be replaced by expressions that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. Their implementation-defined values shall be equal or greaterin magnitude (absolute value) to those shown, with the same sign.
Т.е. int это int16_least_t. Ок.
Например на арме, если я не туплю, uint8 будет с флагом emulated operation но без emulated storage. А на какой-нибудь DSP'шке он получит и emulated storage.
https://devblog.gosso.se/2018/06/how-to-implement-security-txt-under-well-known-in-iis/
https://cybersins.com/howto-resposible-disclosure-with-security-txt/
https://www.bountysource.com/issues/55643936-add-security-txt
https://securitytxt.org/
Тем, кто пишет под такие вот платформы, думаю, не стоит париться о кросс-платформенности.
который полностью соответствует стандарту
но при этом реализует все как попало - 7 бит в байте, 3 байта в инте, поля структуры хранятся в случайном порядке с паддингом, нулевой указатель имеет представление 42.
И заставить, чтобы все программы могли компилироваться под этот компилятор и работать.
https://github.com/Battelle/movfuscator
https://www.cl.cam.ac.uk/~sd601/papers/mov.pdf
Автор даже изобрёл ветвление на mov'ах. Пример:
В результате выполнения в ax будет лежать 1, если si=di, и ноль, если они не равны.
Надо придумать эффективный способ выражения MOV через комбинации этих трёх инструкций.
На поверхности такой вариант: обнуляем регистр с помощью XOR или SUB самого с собой, потом с помощью XOR кладём в него новое значение.
31 бит в инте. А то получается, что padding биты в стандарте зря описаны и нигде реально не встречаются...
Что не помешало в boost preprocessor замутить конечные но достаточно юзабельные циклы.
Т.е. вообще нельзя указатели сравнивать?
Если объекты разные, сравнивать нельзя; если одинаковые, то всё очевидно - не нужно сравнивать. Если неясно, то есть шанс, что объекты разные - нельзя.
Но какой прок от этого? Разные массивы можно хранить в разных адресных пространствах?
UB ради UB, ограничивают полезные возможности.
http://www.libsf.org/li386/indexmain.html
>> но при этом реализует все как попало
Итальянская забастовка!
https://ru.wikipedia.org/wiki/Итальянская_забастовка
Не выйдет, UCHAR_MAX нельзя будет записать. Он должен быть минимум 255.