LINUX.ORG.RU

Авторы Си — наркоманы?

 , , ,


1

5

Столкнулся с интересным багом. После того как разобрался, что же именно происходит, меня постигло крайнее изумление! Оказывается, в языке Си тип числовой константы зависит от формата записи.

Дистиллированный пример кода, который это демонстрирует:

#include <stdbool.h>
#include <stdio.h>

#define IS_HEX(x) \
    _Generic((x), \
        unsigned int: true, \
        long: false \
    )

#define X 0x80000001
#define I 2147483649

int main(void) {
    if(X == I)
        puts("X == I");

    if(!IS_HEX(I))
        puts("I is not hexadecimal");

    if(IS_HEX(X))
        puts("X is hexadecimal");

    return 0;
}

Все три сообщения будут выведены на экран.

Зачем это сделано? Кому от этого легче? Какие оптимизации это позволяет проворачивать, кроме оптимизации отстрела ног программистам? Непонятно! В общем, стремлюсь поделиться своим негодованием здесь и предостеречь будущие поколения от наступления на эти грабли.



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

Это проблема набора библитек и какой результат нужен, не нужна тебе компиляция не используешь, нужна так компилятор тащишь или луа и тп встриваешь в программу.

Вон половина игрушек с собой майковский сборочный инструментарий тащат.

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

s-warus ★★★★★
()
Ответ на: комментарий от yorshka

Ну, да, осталось только целый компилятор с собой притащить.

Любая система с JIT так и делает. Да и gcc достаточно маленький (на фоне ОС), чтобы можно было динамически компилировать.

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

если совсем припёрло можешь ms Variant использовать, но ни кто кроме тех кому с .net общатся надо не использует

s-warus ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU
unsigned char * mem = aligned_alloc(4096/*по памяти*/,size);
mprotect(mem, size, PROT_READ | PROT_EXEC); /*тут я гуглил - "исполняемая память си"*/

Как же ты надоел со своим тупняком… Сколько ж лет уже…

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

Это так называемое UB взялось от того, что на некоторых платформах данные и код сильно отделены друг от друга. На платформах с плоской общей памятью - всё норм.

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

Ну я тебе два раза уже явно демонстрировал, что понятие UB у тебя и у авторов GCC и Clang сильно различается. Но ты всё равно продолжаешь утверждать свои странные вещи, что вот так и эдак делать «можно», это «просто зависит от платформы», etc. Странный ты человек.

shdown ★★
()
Ответ на: комментарий от LINUX-ORG-RU

Это просто приведение типа указателя, какое расширение?

Такое приведение типа ( от функции к void* или char* и обратно ) уже выходит за рамки стандарта.

algo
()
Ответ на: комментарий от yorshka

Да хоть сверхвысокоуровневой её называй, как бидон. Но если уж говорить что-то о низком уровне, то взяв голую железку у тебя пути нет кроме как сначала, что-то на родном ассемблере написать, затем к этому добавить сишные функции с ассемблерными вставками для дрыгания специфичное железу, затем уже поверх этого утилитарные Си интерфесы наладить, а уже потом приходит вся другая арава языков и могут начинать работать. Си, как и любой другой язык восседающий на вершине 100500 абстракций как от ОС так и аппаратных, высокоуровневый. Но, если уж дело заходит до низкого уровня, то Сишка там может, порой ещё и обрезанная, но тем не менее. Ну, тут такое, войны определений что считать низким уровнем, ты вот (как я понял) хочешь однозначности в преобразовании в ASM, ну вроде справедливое желание, но оно физически невыполнимо, покуда существует хоть одна оптимизация. Но всё же, более менее можно понять и с большой долей вероятности предположить что будет и как в си больше чем в других языках. Может не везде и всегда, но в точечных случаях, какого-то критического места да.

Ъ низкойровневый язык это препроцессор сишный хехее, там можно вставками всё сделать. 100% предсказуемость и прямое управление компуктером через мнемоники.

Хотя нет! Можно сделать так написать вручную main.s программу на ассемблере, а затем!

gcc -S -O3 main.s -o out.s

Вуаля, main.s тут выступает в роли высокоуровнего языка, а out.s непредсказуемый результат, прям как сишка. Только вот тут ассемблер, куда тут ещё ниже. Так что называть язык точно не низкоуровневым потому что нет 100% предсказуемости преобразования синтаксической конструкции к нативному ассемблеру такое себе.

Это всё просто мысли в слух, тред весёлый, сритесь дальше =) А я нуб, фигню всякую несу глупую.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от shdown

Это даже не UB. Его просто нет.

Это расширение, но расширение очень распространенное на обычных «фон-неймановских» платформах.

О чём в приложении J и написано:

J.5 Common extensions

The following extensions are widely used in many systems, but are not portable to all implemen-tations. The inclusion of any extension that may cause a strictly conforming program to become invalid renders an implementation nonconforming.

J.5.7 Function pointer casts

  1. A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (6.5.4).

  2. A pointer to a function may be cast to a pointer to an object or to void, allowing a function to be inspected or modified (for example, by a debugger) (6.5.4).

algo
()
Ответ на: комментарий от shdown

делать «можно», это «просто зависит от платформы», etc.

Если разработчики «платформы» доопределили поведение, то «можно», не выходя за рамки платформы.

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

Если разработчики «платформы» доопределили поведение, то «можно», не выходя за рамки платформы.

А «платформа» — это что такое? Реализация (GCC + glibc)? Или аппаратная платформа (x86-64)?

shdown ★★
()
Ответ на: комментарий от LINUX-ORG-RU

Но если уж говорить что-то о низком уровне, то взяв голую железку у тебя пути нет кроме как сначала, что-то на родном ассемблере написать, затем к этому добавить сишные функции с ассемблерными вставками для дрыгания специфичное железу, затем уже поверх этого утилитарные Си интерфесы наладить, а уже потом приходит вся другая арава языков и могут начинать работать.

Каково там в 80х живётся, а? Мой совет, и запиши его куда-нибудь: в 2009 году появится такая штука как биткоин, купи его побольше и не продавай года до 2024. Окупится!

А по факту, вот как твой сценарий выглядит в современном мире: для существующего компилятора ЛЮБОГО языка пишется новый кодогенератор и всё, можно кросскомпилировать существующий софт. Ни на каком родном ассемблере писать ничего кроме пары функций не требуется. Сишечка тут тоже не особо нужна, можно взять сразу Rust. Правда, кроме RISC-V новых ISA не выходило уже лет 10-15 точно (AArch64 вышел в 2011).

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

Согласен. Но реализации языка Си в виде GCC и Clang не доопределяют ничего из того, о чём говорил firkax.

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

Я «художник», мне можно. А так что не так? Указатель на функцию обязан быть выровненным, выровнять по границе страницы памяти, 4 КБ это 99% случаев, сам по себе весь код шиза работающая на честном слове, а ты до мелочи докопался =) Ну а, по поводу mprotect второй раз в жизни потребовалась исполняемая память и оба раза это было на ЛОРе для просто примера, там где-то было про Jit, а тут чуть другое.

Касты указатель на данные <-> указатель на функцию — это UB по стандарту.

Да, ибо память разная, да и не только это, рандомизаци адресов всякие и прочее.
Если уж говорить про стандарты, то не постандарту всё что разное на разных платформах. Но, если мы разрабатываем ПО например для игровой консоли или типа того, у нас аппаратная платформа фиксирована, и вещи которые де юро не по стандарту или/и UB, де факто стандартны для платформы и в её рамках UB не являются, так как для существования UB должен быть момент с наличием вариативности. Если её нет, то UB не существует, исключительно в рамках платформы, но всё же.

Так что когда мы пишем код для всего и вся, то да любая разность в платфрмах либо вне стандарта вовсе или в UB, а когда мы пишем код для конкретной аппаратной платформы (а это не редкость) практически все UB испаряются и implementation defined тоже ибо SDK один за всех и все за одного =)

Ты прав конечно, в целом, но есть частности где эта правота чисто бумажная, а на деле происходит лютая и намеренная платформозависимая специфика. Которая не то что UB, а гарантированно развалится или будет делать дичь, а не работать на другом железе.


Как же ты надоел

Если я тебя нервирую, добавь меня в игнор и делов =) Я вот тоже знаю парочку вроде хороших людей, но они меня бесят. Бывает.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от yorshka

А по факту, вот как твой сценарий выглядит в современном мире: для существующего компилятора ЛЮБОГО языка пишется новый кодогенератор и всё

Ой да кто там чего пишет сейчас, все свою нашлёпку над LLVM делают и всё, а дальше оно само =) А что там происходит после его IR понятия не имеют. Я утрирую, но чего не так чтоль?

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от shdown

Ну сначала ты stdlib забыл =)

В куче пересечение помеченой памяти и нет и кря или/и кратно ещё странице памяти, относительно адреса кучи, а надо прям относительно и размера страницы и самих страниц, как там ядро у себя их держит. Вроде… А через что тогда память брать для такого, через mmap только получается?

Ну, а так, туше. Интересно, спасибо. Ну и если не лень можешь дополнительно пояснить какиенить детали =) Но если будет что прочесть, прочту завтра.

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

Ну сначала ты stdlib забыл =)

Первая строчка файла буквально.

В куче пересечение помеченой памяти и нет и кря или/и кратно ещё странице памяти, относительно адреса кучи, а надо прям относительно и размера страницы и самих страниц, как там ядро у себя их держит. Вроде…

Примерно. Я не понял только про «кратно ещё странице памяти».

А через что тогда память брать для такого, через mmap только получается?

Конечно. В стандартах же везде написано что-то вроде: munmap() можно применять только к результату mmap(), иначе behavior is undefined.

Вот тебе, кстати, пример с aligned_alloc: https://godbolt.org/z/nTK8b6esn

Ну и если не лень можешь дополнительно пояснить какиенить детали =)

Какие?

shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

мы пишем код для конкретной аппаратной платформы (а это не редкость) практически все UB испаряются

Вариативность возможна даже не для платформы, а для одного устройства.

Обновили прошивку, и поведение процессора изменилось. Или в ходе ремонта пришлось заменить чип на другую его ревизию.

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

Или для другой компиляции на этом же устройстве той же версией компилятора и с теми же файлами. Достаточно сделать #include </dev/urandom>.

</shitpost>

shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

когда мы пишем код для конкретной аппаратной платформы (а это не редкость) практически все UB испаряются

Чо? Дядя, большая часть пишущих код на сишечке под лялекс кроме x86_64 ничего в жизни и не видели, но тем не менее UB у них выстреливает с завидной регулярностью.

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

наркоманы те кто продолжает сишку по доброй воле использовать

Да я бы и не против что-нибудь паскалеподобное использовать, например Аду, но увы - вокруг всё на си. Хочешь какой-нибудь готовый код позаимствовать для своей самоделки - а он с высокой вероятностью найдется только сишный.

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

int 1000000000*10 = скорее всего что-то битое).

Причем что хуже - битое оно будет молча. Например складываем два инта, для результата выделяем long чтобы не переполнилось. Казалось бы всё предусмотрели. Но нет, сишный компилятор сложит два инта, результат молча обрежет до инта, и присвоит лонгу. Чисто «ассемблерное» поведение, на что натыкаются те кто асм не знает. Предупреждения не будет даже с -WAll и -pedantic. А вот Ада в этом случае работает именно как ожидалось от языка высокого уровня. (это всё было про классический 32-битный х86, что будет на 64-битных системах я не проверял)

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

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

А если результат не лезет в то, что выделили для результата?

koko
()
Ответ на: комментарий от yorshka

Да, я перегнул вчера палку. Можно было бы скромнее и конкретнее написать про более предсказуемую платформу, ну например модель памяти внезапно не поменяется если программно-аппаратный комплекс с фиксированным SDK и правилами сборки имеется. Ну и x86_64 это смотря какой *-v1 *-v2 *-v3. В обсуждениях тут слишком далеко прыгаем то по аппаратной части с гарвардской архитектуры памяти на фон неймановскую, то по программной части в соглашениях long на винде vs long на линуксе и так далее.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от shdown

Первая строчка файла буквально.

👍

Примерно.

Понял

Я не понял только про «кратно ещё странице памяти».

Тут мне показалось что есть какие-то особенности операционной системы в плане памяти для исполняемого кода, типа оно складывается куда-то линейно, а потом мапиться… Короче, начал гадать о implementation defined, ибо там может быть что угодно.

Конечно. В стандартах же везде написано что-то вроде: munmap() можно применять только к результату mmap()

Спасибо. Еслиб я его/их читал =))

Какие?

А всё, ты всё написал. А так, для меня сишечка в первую очередь язык описания более приземлённых данных и манипуляций с ними, а особенности механизмов работы с памятью являющиеся чистой программной абстракцией, зависящей от стандартов для определённых семейств операционных систем, трогать приходится исключительно редко. Иными словами была бы у malloc реализация такая что он не хранил метаданные рядом с данными указатель на который выдаёт, и выравнивал бы он бы всё по страницам то всё бы было ок, но было бы не ок в других планах. Я не оправдываюсь, желательно конечно знать стандарты наизусть или близко к этому, плюс знать все нюансы интерфейсов операционных систем, а не только POSIX. Но в целом к языку это отношения особого не имеет, и так уж сложилось что лично мне касаться всего этого нужно редко. Ну как всего, выделять выровненную память для последующего её исполнения уж точно редко =) Хотя это конечно интересно, можно очень увлекательно играться в Jit например, но это уже дорога если не длинною в жизнь, то в четверть её точно.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

да, а что? тебе отсыпать что ли, свое закончилось?

olelookoe ★★★★
()

ходють тут всякие, ходють…
весь подъезд заплевали уже…
прррроститутки! наркоманы!

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

Сказал лиспер сидя на лавочке.
И поправив платочек, снова принялся рисовать на песке скобочки тростью, раз за разом затаптываемые прохожими.

ЛАВСАН! раздался детский голос из за кустов, и три пары сверкающих пяток сандалей сишников, со звонким смехом побежали прочь, за гаражи приводить указатели к воиду.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Большая часть нытья про UB в багзилле GCC и LLVM выглядит так:

  1. чуваки написали говнокод, он вроде работает
  2. чуваки обновили компилятор
  3. говнокод сломался
  4. АААААА ПЛАХОЙ КАМПИЛЯТАР

Т.е. сишечка тебе подходит только если ты готов никогда не менять компилятор, его версию и флаги сборки. И тогда возникает вопрос: нахрена сишечке стандарт?

yorshka
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Всё читают в интернете
И совсем не курят маны,
Лишь юзают нейросети —
Проститутки! Наркоманы!

Скобки от конца до края
Ставят, это вам не шутки,
Борщ последний доедая,
Наркоманы! Проститутки!

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

Хитрожопый =) Ты задаёшь такие общие короткие вопросы, что на них нужны настолько огромные и многогранные ответы, что я… пойду лучше чай пить. Лучше задай этот вопрос кому-то умному, но тоже любителю простыней, пусть распишет всё.

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

я нипонялЪ. это ты меня лиспером обозвал, штоле? это было обидно! требую сатисфакции! или хрен с ним, не так уж и обидно. но все равно я этот, как его… забыл уже… но не лиспер!

норкоманы…

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

сишечка тебе подходит только если ты готов никогда не менять компилятор

о, это же я! это про меня! пошёл за гаражи, к войду указатели кастить…

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

только если ты готов никогда не менять компилятор, его версию и флаги сборки

По-хорошему версия компилятора должны быть указана в build-dep твоего проекта, а флаги компиляции - в сборочном скрипте - т.е. флаги это часть исходного кода проги. Изменение флагов компиляции должно приравниваться к пропатчиванию других частей исходника. То есть если хочешь меняй, но что у тебя в итоге получится - смотри сам. Если не программист - лучше не меняй.

нахрена сишечке стандарт?

Стандарт нужен в качестве обзора общих тенденций работы компиляторов. И именно в таком качестве писался C89. Потом они что-то попутали и решили что могут сами что-то придумывать. А так ну вот смотри - почитал ты стандарт, примерно знаешь язык. Потом читаешь описание компилятора, уточняешь детали по месту - где совпадает со стандартом, где не совпадает, какие доп. фичи. А без стандарта пришлось бы каждый компилятор с нуля изучать.

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

Чего это новый? В K&R C тоже препроцессор есть.

И что sign extension? Если передать в функцию char -1 она до C89 превращалась в int 255 т.к. расширение беззнаковое?

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

Дак это ж только подтверждает тезис, что указатель — не число. Потому что иначе бы работали простые операторы сравнения. Больше, меньше. Но они не работают. Не везде работают. А чтобы было везде, создателям библиотеки С++ пришлось сделать свой компаратор! Который, кстати, по-разному реализован для разных платформ. Это доказывает именно, что указатель не число.

Скажи, а если я напишу класс домашних животных, сделаю от него классы кошек и собак. И напишу компаратор для объектов кошка и собака. Для тебя они тоже будут числами?

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

напишу компаратор для объектов кошка и собака

эка тебя разобрало, милок. без компаратора уже не различаешь?

olelookoe ★★★★
()

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

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

Каникулы же вроде наступили, выпускной вон был вчера.

Вот у людей время и появилось свободное…

PunkPerson
()
Ответ на: комментарий от firkax

Изменение флагов компиляции должно приравниваться к пропатчиванию других частей исходника.

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

То есть если хочешь меняй, но что у тебя в итоге получится - смотри сам.

Вот теперь ты сам понимаешь, почему от C стараются избавляться где только можно?

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

Ну он там рядом со свечкой стоял. Как и все эти дядьки.

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

от C стараются избавляться где только можно

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

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

Вот теперь ты сам понимаешь, почему от C стараются избавляться где только можно?

Нет, почему?

Zhbert ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.