- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
#include <stdio.h>
#include <stdlib.h>
int * ptr;
int * getptr()
{
puts("getptr");
return ptr;
}
int jump()
{
puts("jump");
ptr = (int*)malloc(sizeof(int));
return 1337;
}
int main()
{
ptr = (int*)malloc(sizeof(int));
*ptr = 0;
*( getptr() ) = 1;
printf( "*ptr = %i\n\n", *ptr );
*( getptr() ) = (jump(), 100);
printf( "*ptr = %i\n\n", *ptr );
*( getptr() ) = jump();
printf( "*ptr = %i\n\n", *ptr );
return 0;
}
Пример с 100 работает из-за наличия "точки следования" в виде оператора ,
- частично вычисляется левая часть = (выполняется getptr())
- вычисляется правая часть (выполняется jump())
- продолжает вычисляться левая часть (выполняется *)
не, ну это КАК ВООБЩЕ?
т.е. есть оператор =, у него 2 операнда, и компилятор такой взял чучуть посчитал слева, потом чучуть справа, потом подумал решил снова влево посчитать
тест №2:
- вычисляется правая часть (выполняется jump() и ",")
- вычисляется левая часть = (выполняется getptr() и потом *)
каким таким боком "," внутри правого операнда влияет на то, когда в левом операнде будет посчитано значение в скобках (getptr()) - до или после вычисления правого операнда???
Это же UB, он имеет право что угодно сделать. При включенной оптмизации компелятор вообще может выкинуть UB код: дескать можно вообще ничего не делать, раз UB.
правильнее: что бы разрешить компилерам делать что угодно (== агресивная оптимизация вызовов функций), стандарт оставляет это как UB.
я не говорил про общий случай. я говорил про конкретный случай, проиллюстрированый в говнокоде.
стандарт может сделать корректным код сверху, но это преднамеренно не делается.
WAS THIS PAGE HELPFUL? YES/NO. TELL US MORE. YOUR OPINION IS IMPORTANT TO US!
В процессорах x86 есть похожий хак: инструкция LEA. Она тоже не читает данные, а просто вычисляет их адрес.
> Принципиально то, что синтаксический сахар, теоретически, всегда можно удалить из языка без потери его возможностей — всё, что можно написать с применением синтаксического сахара, может быть написано на этом же языке и без него. Таким образом, синтаксический сахар предназначен лишь для того, чтобы сделать более удобным для программиста написание программы.
Допустим:
И как это переносимо написать без sizeof? Создавать массив из двух элементов struct shit и вычитать разницу адресов между нулевым и первым элементом для такого массива? Такой подход будет неточным.
Для одной структуры с учетом выравниваний полей допустим будет такая хуита:
Но если сделать массив из двух таких структур, этот uint8_t e уже сожрет себе все 4 байта, и разница между одним и другим указателем в массиве из двух таких структур будет не равна размеру одной структуры в байтах
1) равна, т.к. размер структуры включает паддинги
2) и соответственно sizeof возвращает ровно количество байт между двумя структурами в массиве
Ты же знаешь, что ОС всё равно блоками пишет, да?
Вобщем-то сишечка довольно убогий язык, но в плюсах-то эту проблему решили же, да?
Я так и делал всегда. Там же строки могут быть, указатели, вот это всё. Плюс byte order иногда важен. Просто пишешь простенький сериализатор/десериализатор и не выёживаешься. Ну или просто используешь какой-нибудь asn1/protobuf.
> Там же строки могут быть, указатели, вот это всё.
Можно придумать некий внутриязыковой механизм, который бы позволял программировать все такие вариации, скажем
В общем тут как раз таки гомоиконность нужна. В плюсах есть лишь какие-то ограниченные костыли, вроде констэкспров, шаблонов. Есть ли какие-нибудь способы распарсить в компилтайме тип структуры (из чего она состоит) и на основе этого порождать некий код, который что-то там должен делать?
Пока только ограниченное говно типа boost::fusion, где поля надо руками перечислять (типы само надёргает).
Но обещают завезти нормальную рефлексию и кодогенерецию. Лет через 5-10.
а завезут метушню
У кодогенераторов есть преимущество: они могут генерить код на разных языках из одного описания.
Правда при этом приходится добавлять ещё один язык для таких описаний...
... что не обязательно является чем-то плохим.
Так-то в каком-нибудь CL можно один раз написать макрос и генерить из сериализаторы/десериализаторы/парсеры/валидаторы/модули для nodejs/даже небо/даже аллаха. Но люди продолжают придумывать новые, более другие языки.
иными словами sizeof(*bar) всегда есть sizeof(bar) даже если bar это данглинг поинтер?
Ну звучит логично: не надо разыменовывать
В swift, я думаю, что тоже UB нет (во всяк случае ябловый UBSanitizer в шланге работает только для C)
Но UB там возникает не на ровном месте, в отличии от плюсов и сишки
ну так-то оно и в Java есть sun.misc.Unsafe
Даже в питоне можно взять cTypes и стригеррить черте-что
Мы же про "нормальное" использование языка.
> Если кратко, то содержание поста сводится к рассмотрению следующего примера:
> Строка в C# представляет собой последовательность слов в UTF-16. А значение "X\ud800Y" не особо хорошее, т.к. включает в себя старшее слово суррогатной пары 0xD800, после которого должно бы идти младшее слово (интервал 0xDC00..0xDFFF), но вместо него идёт Y (0x0059). Проблемы начинаются из-за того, что в IL-коде для хранения аргументов конструктора атрибута используется UTF-8. Впрочем, у Джона Скита всё очень хорошо расписано, всем советую прочитать оригинальный пост.
> Меня заинтересовало, как же будут себя вести MS.NET и Mono в этой непростой ситуации (подробная заметка). А вести они себя будут по-разному. Первое различие можно увидеть во время компиляции. MS.NET положит значение строки в метаданные в виде 58 ED A0 80 59, а Mono — в виде 58 59 BF BD 00 (оба значения являются невалидными UTF-8 строчками). Второе различие можно пронаблюдать запустив полученные приложения. MS.NET сможет запустить обе версии и успешно достанет значение аргумента атрибута (в виде 0058 fffd fffd 0059 и 0058 0059 fffd fffd 0000 соответственно), а Mono поперхнётся настолько невалидной строкой и вернёт null в каждом из случаев. Из-за этого маленький пример Джона Скита сразу упал, когда я попытался запустить его под Mono.
Это дыра в стандарте
[quote]
According to the ECMA-334 document (p. 473):
A program that does not contain any occurrences of the unsafe modifier cannot exhibit any undefined behavior.
[/quote]
Но вообще мой cl четко видит тут три буквы: первая и последняя обычные, а средняя занимает 3 байта в UTF-8 (мне кажется это какой-то такой плейн где всякие asian languages, а нет, это невалидная хуйня (которую уникод обозначает значком [?]) )
Это не UB
Ведроид бывает
1) не только на arm (mips, atom)
2) 90% софта там писано на java/kotlin под ART. А там действуют правила JMM и JLS.
зы: ну ты понимаешь же что с weak memory model можно прекрасно жить, как и с любой другой memory model, главное не завязываться на странные спец-эффекты.
Любой CPU всегда можно попросить не реордерить ничего (обычно с помощью интринсика или ключевого слова ЯПа, которое затем превращается в инструкцию типа fence или как-то так)
понятно что жить можно и любой подводный камень можно переступить
но должно же быть какоето объяснение феномену...
на вики пишут что косяки JMM с 2004 года недействительны
У JMM нет UB кроме race conditions, но это не совсем UB так как не зависит от компилятора (а зависит от количества ядер, шедулера операционной системы, количества и тяжести других процессов, и месяца китайского календаря).
Объяснение очень простое: чем слабее гарантии -- тем больше свободы у инженеров в разработке проца, а значит тем лучше он у них может получиться.
Ты ведь наверное тоже не любишь делать свои интерфейсы и API публичными, что бы на них сразу же завязались 150 человек, и ты бы потом не мог их отрефакторить
Там всё, как тебе нравится: https://ideone.com/IY0KUp
Напрямую к ним обратиться нельзя - это синтаксически неверно. Но если использовать $$, то именем переменной может быть любая строка и, следовательно, что угодно, что в нее конвертится.
https://ideone.com/svS2sO
P.S. Это можно публиковать отдельным говнокодом.