LINUX.ORG.RU

Linux перейдёт на использование стандарта C11 в версии 5.18 или одной из следующих

 , ,


1

1

Во время обсуждения набора патчей, связанных с исправлением уязвимостей класса Spectre в коде для работы со связанными списками, стало ясно, что проблему удалось бы решить более изящно, если бы в ядро допускался код, использующий стандарт старше C89. Сейчас код в ядре должен соответствовать С89 (с GNU расширениями) на основе спецификации, сформированной ещё в 1989 году. Связанная со Spectre проблема была в том, что для перебора элементов списка используется макрос. Так как переменная цикла передаётся в этот макрос, то она определяется вне самого цикла и остаётся доступна после цикла. Использование более новых стандартов языка C позволит определять переменные для цикла прямо в блоке for.

В связи с этим, Линус Торвальдс предложил попробовать перейти в ядре 5.18 на стандарт C99, который был опубликован в 1999 году, на что получил встречное предложение перейти сразу на C11. При проверке сборки в GCC и Clang с новым стандартом проблем пока не возникло и, если при более тщательном тестировании ситуация не изменится, в сборочных скриптах ядра 5.18 опция --std=gnu89 будет заменена на --std=gnu11 -Wno-shift-negative-value.

В случае неудачи, переход будет отложен на один из следующих выпусков.

>>> Подробности



Проверено: xaizek ()
Последнее исправление: maxcom (всего исправлений: 5)
Ответ на: комментарий от X512

Прикол в том, что лично я про atomic-типы узнал лишь в прошлом году, позор на мою седую голову!!! Теперь пользуюсь. Радуюсь: намного меньше лишних мьютексов пихать в код приходится. Если б я еще смог осилить С++20… Но каждый раз, глядя в эту жесть с прототипами, где шаблоном шаблон погоняют, у меня волосы дыбом встают! Нафиг-нафиг…

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

C11 это всё ещё каменный топор кстати

Обижаешь. Обсидиановый нож же. Для низкоуровщины все равно лучше ничего не сделаешь в рамках имеющейся модели центральных процессоров. И нет, раст ни низком уровне не лучше и не хуже — он просто такой же, как C11.

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

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

Уже теряет актуальность, если она там была.

Да вот нет. Кому не актуально обычно пишут на других языках.

И ты говоришь синтаксическая обёртка так, будто это что-то плохое, когда плохое это или нет зависит от контекста.

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

Так я угадал, что ты пишешь под микроконтроллеры или нет?

Мог бы, но в данный момент нет.

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

Я даже объявлять переменные где-то кроме начала функций (именно функций а не любых блоков {}) избегаю, хотя это разрешено в C89

Ты упрт? Даже в паскале вводят возможность объявлять переменные не в начале, потому что это тупо удобно. А вся индустрия движется к тому, чтобы вообще не объявлять переменные, поскольку это бессмысленный ручной труд, подверженный ошибкам. Ну типа ты же не объявляешь тип промежуточных переменных в выражении a = b + c + d + e? Как же так, а вдруг b + c имеет иной тип, нежели a? А вот потому что простое должно быть простым, а сложное — возможным.

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

это всего лишь доказывает, что нормальным разрабам и 30 летний стандарт не мешает

Я в треде
Опрос: Три-пять лучших фич C++ (комментарий)
как раз доказывают одному гражданину, что стиль кода именно больше значения, чем особенности ЯП. Можно писать плохо на расте, можно писать хорошо на сишке. Что не отменяет того факта, что водителю-асу на мерседесе ездить приятнее, чем на жигулях.

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

Я выше уже отвечал ( Linux перейдёт на использование стандарта C11 в версии 5.18 или одной из следующих (комментарий) ) - современные компиляторы умеют его использовать динамически и без помощи скопов, а просто видя области использования переменных.

Нужность промежуточных sub sp add sp под большим сомнением, можно просто слоты для d,e,f совместить с слотами для g,h,i. Если из мест, где ни d,e,f ни g,h,i не используются, не вызываются ещё функции - то точно не нужны и будут лишь тратой времени. Если вызываются - ну, можно сэкономить занятыё стек перед вызываемой функцией, но насколько оно того стоит - опять спорно. Тяжёлые выделения стека всё равно делать так в блоках не надо.

И с другой стороны вот такой код:

void foo() {
  char s1[200], s2[200];
  fgets(s1, ...); fgets(s2, ...);
  (тут что-то делаем с s1)
  foo2();
  (тут что-то делаем с s2)
  LOG("s1=%s, s2=%s", s1, s2);
}
Допустим, LOG это макрос, в прод-версии отключаемый. Тогда получится, что можно перед вызовом foo2() сделать add sp,200 (выкинув более ненужное s1). Я не знаю, делают ли так компиляторы, но по-моему ситуация тут полностью аналогичная твоему примеру, и отсюда очевидно, что скопы тут ни при чём.

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

Пример приводи. Я что-то не видел новых возможностей отстрелить себе ногу. Зато плюшек — вагон!

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

Насколько в ядре важны именно GNU расширения?

Потому что ANSI C — редкостный кусок дерьма, высранный бестолковым коммитетом. Не то, чтобы K&R был лучше, но создавался хотя бы реальными программистами, а не вахтерами. Например, хочется возвращать значение из макроса. Например, неплохо было бы получать адреса меток для программирования конечных автоматов через быстрый goto, а не убогий switch-case. Вложенные функции, указатель на пустой массив-поле в структуре с динамическим размером, упомянутый typeof — и еще мелкие, но очень приятные фичи, без которых писать на сишке тех лет было болью и страданием. Солидная доля этих фич уже попала в стандарт, но стандарт всегда будет отставать в развитии, потому что стандарт пишут комитетские макаки, а не грамотные программисты.

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

Вот где настоящие ретрограды:

In practice this means code must conform to C89, with some C99 features allowed

Да, есть такое.

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

Вангую, что у тебя или преждевремменная оптимизация всего на свете или какая-то специфическая ниша, где оптимизация всего на свете нужна. Даже если мы упрощаем и говорим, что при такой инициализации мы прячем вызов memset, то как минимум спрятать вызов memset бывает лучше из-за того, что в memset можно ошибиться (+ всем надоевший пример, когда компилятор выкидывает вызов memset для оптимизации, т.к. этот пример в нашем случае не важен). Не надо цепляться именно к str, назови эту переменную buf, который надо занулить весь, чем вот это:

char buf[BUF_SIZE] = {0};

будет хуже чем это:

char buf[BUF_SIZE];

memset(buf, 0, sizeof(buf));

мне не понять. sizeof то хоть одобряешь? Или тоже надо явно прописать BUF_SIZE в вызове memset?

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

Конкретные вариации spectre, которые были обнаружены и задокументированы - да, исправили. Spectre широком смысле - не будет пофикшен, пока процессоры не откажутся от спекулятивного выполнения, то есть никогда, ибо производительность.

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

Ну типа ты же не объявляешь тип промежуточных переменных в выражении a = b + c + d + e? Как же так, а вдруг b + c имеет иной тип, нежели a?

Зря ты это написал, тайпкасты промежуточных операций в выражениях - весьма нужная вещь, от них может совсем меняться смысл формулы. Например:

char a, b, c;
a = 100; b = 120;
c = (a+b)/2;
или
char a, b, c;
a = 100; b = 120;
c = ((char)(a+b))/2;
Первый код безопасно считает среднее арифметическое (110), потому что тайпкастит аргументы к int-у. Второй - делает побитово-строгую 8-битную знаковую арифметику: 100+120=-36, ответ будет -18.

Или так:

int a, b, c;
a = 1000000000; b = 1200000000;
c = (a+b)/2;
или
int a, b, c;
a = 1000000000; b = 1200000000;
c = ((int64)a+(int64)b)/2;
Первый код делает побитово-строгую 32-битную арифметку, ответ будет -1047483648. Второй же считает среднее арифметическое за счёт явного тайпкаста с ответом 1100000000.

А вся индустрия движется к тому, чтобы вообще не объявлять переменные

Да я в курсе, js/php/что-там-ещё очень популярны.

бессмысленный ручной труд

Кажется это описание того, чем занимаются 90% js/php-писателей.

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

A function with external linkage is declared with an inline function specifier, but is not also defined in the same translation unit

Как пример.

cat sample.c 
static int n = 5;

void inline foo() { n = 66; }
void inline foo();

int main () {
    return 0;
}
gcc sample.c 
sample.c:3:21: предупреждение: «n» статическая, но используется в inline функции «foo», не являющейся статической
    3 | void inline foo() { n = 66; }
[

Если в четвертой строке убрать inline - варнинга нет.

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

Да я в курсе, js/php/что-там-ещё очень популярны.

Кажется это описание того, чем занимаются 90% js/php-писателей.

Ну начинается :) Если у тебя элитизм а не суровая необходимость, тогда не интересно.

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

Потому что ANSI C — редкостный кусок дерьма, высранный бестолковым коммитетом. Не то, чтобы K&R был лучше, но создавался хотя бы реальными программистами, а не вахтерами.

Ты опять всё перепутал.

ANSI C это как раз нормальный документ, они там ничего сами не придумывали, только обобщили и зафиксировали имеющееся, созданное реальными программистами. Это потом (C99+) они решили сами придумывать (и то не всё), получалось не очень.

K&R хуже, он хоть и создан тоже программистами, но ещё не успел нормально оформиться.

А от ANSI продолжилось развитие тем же gcc и другими, но теперь уже некому обобщать в единый документ всё.

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

грамотные программисты

скоро превратят язык в функцию Дирихле.

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

Вангую, что у тебя или преждевремменная оптимизация всего на свете

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

который надо занулить весь

я ж писал про это:

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

чем вот это будет хуже чем это:

Тем что = {0} выглядит как статическая преинициализация компилятором, а тут вместо неё memset.

в memset можно ошибиться

Ну, я bzero предпочитаю, memset написал чтобы не создавать левых дискуссий но видимо надо было наоборот.

sizeof то хоть одобряешь

А что с ним не так? Наоборот лучше чем дублировать размер в двух местах, можно потом забыть его исправить в одном из них.

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

С realloc еще добавили.

https://stackoverflow.com/questions/40065322/realloc-lifetime-and-ub

All undefined behavior shall be limited to bounded undefined behavior, except for the following which are permitted to result in critical undefined behavior: The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3). C11

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

Первый код безопасно считает среднее арифметическое (110), потому что тайпкастит аргументы к int-у. Второй - делает побитово-строгую 8-битную знаковую арифметику: 100+120=-36, ответ будет -18

Второй код делает UB, потому всем пофик.

Да я в курсе, js/php/что-там-ещё очень популярны.

F#, Rust, Go, Haskell, Kotlin.

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

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

Тебе не приходило в голову, что часть из того, что ты зовешь «созданное реальными программистами» таки изначально было высрано манагерами? А потом уже реализовано и подхвачено реальными программистами за зарплату.

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

Переполнение целочисленного типа — не UB!

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

Оно UB только с -O2/-O3 без -fno-strict-overflow.

Ну да ладно, можешь с unsigned типами то же самое сделать, оно никогда не UB.

unsigned char, (100+200)/2

unsigned int, (2000000000+3000000000)/2

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

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

В моем понимании, вот это твое:

Тем что = {0} выглядит как статическая преинициализация компилятором, а тут вместо неё memset.

И есть создание проблем на ровном месте. Что оно тебе дает, кроме каких-то представлений о сгенеренном коде сразу и дополнительной писанины в виде вызовов memset/bzero непонятно. Ты можешь ошибиться не только в параметрах memset/bzero, ты можешь забыть написать вызов этой функции для переменной. В случае с инициализацией при объявлении инициализация сразу перед глазами, не надо искать проинициализировал ли ты её или нет ниже по коду.

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

sizeof то хоть одобряешь

А что с ним не так?

Я не говорил, что с ним что-то не так. Но у тебя агрументы про «выглядит как», я и задал вопрос, чтобы проверить, может и sizeof не так как-то для тебя выглядит.

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

Что может быть тупее чем требование объявлять счётчик цикла в начале блока кода, когда цикл в конце? Но линуксоидам и так сойдёт.

Тупее может быть только malloc()/free(), про которые вы потом благополучно забудете или сделаете free() дважды, потому что мозг человека не может держать в голове больше ~20 строчек кода. В ядре названия функций другие, но суть не меняется - и огромных функций там до черта.

// b.

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

Оно UB только с -O2/-O3 без -fno-strict-overflow

О, сишник из палаты мер и весов. Что такое UB - за все годы так и не понял. Си никогда не видел, пишет на языке gcc.

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

Отлично ты его подловил😁

А коммент про -O2 показывает полное отсутствие понимания что же это такое.

И вот «тайпкаст». По крайней мере в C++ это называется integer promotion.

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

критических усложнений вроде не было

Ага, конечно. VLA, из-за которых локальные переменные, ранее представлявшие собой константное смещение относительно реперной точки стека, превращаются в выражения произвольной сложности, для вычисления которых может не хватить регистров – это, конечно, совсем никакое не критическое усложнение.

Коротко говоря: деятельность стандартизаторов направлена на уничтожение языка. Вся целиком.

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

Тебя папа с мамой делали совершенно ретроградским, несовременным и немодным способом которому сотни миллионов, если не миллиард лет. Но ты, конечно, можешь смело тестировать новые, модные, стильные и молодежные способы. Получится вряд ли, но прослывешь «прогрессивным» и «продвигающем новое».

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

Для оптимизирующего компилятора это не совсем так. Как минимум, иногда гляжу дизассемблером, там на 100500 переменных часто значительно меньше push/pop и регистров. Т.е. утверждение верно только для -O0

hatred ★★★
()

Ну наконец-то эта эстонская стыдоба закончится!

zabbal ★★★★★
()

Связанная со Spectre проблема была в том, что для перебора элементов списка используется макрос. Так как переменная цикла передаётся в этот макрос, то она определяется вне самого цикла и остаётся доступна после цикла. Использование более новых стандартов языка C позволит определять переменные для цикла прямо в блоке for.

Ппц, всегда считал что 99% проблем в прогах, что не читают свой же код.

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

Я для тебя открою секрет, но переменные могут не занимать место в стеке вообще. Иногда даже и регистра не занимают.

Процессор все равно ровно то, что ты написал, даже на ассемблере, исполнять не будет. Он будет исполнять что-то другое, что работает гораздо быстрее, но дает тот же результат. Тот же результат - defined behavior.

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

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

А вся индустрия движется к тому, чтобы вообще не объявлять переменные, поскольку это бессмысленный ручной труд, подверженный ошибкам.

Вообще-то объявление переменных - это та самая избыточная информация, благодоря которой компилятор находит определенный класс ошибок.

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

Оно UB только с -O2/-O3 без -fno-strict-overflow.

Типа int не обязан быть 32бит поэтому и UB

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

А вся индустрия движется к тому, чтобы вообще не объявлять переменные, поскольку это бессмысленный ручной труд, подверженный ошибкам

Как раз НЕобъявление переменных способно увеличить количество ошибок и делает код менее надёжным.

ты же не объявляешь тип промежуточных переменных

В простых случаях — не объявляю. В неочевидных приходится и явное преобразование делать.

Вообще, объявление переменных «по месту» — это скорее хорошо, чем плохо. Но хорошо не потому, что «тупо удобно», а потому, что позволяет избежать неинициализированных переменных.

Вообще, не надо забывать про сопровождение кода. Я лучше один раз напишу double, чем в течение нескольких лет буду заглядывать туда и вспоминать «а какой же тут тип, и правильно ли я сделал, положившись на его приведение по умолчанию». Долбёжка по клавишам — очень небольшая часть работы программиста.

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

Это потом (C99+) они решили сами придумывать (и то не всё), получалось не очень.

Вот не надо у меня мои stdint и stdbool отнимать. Без первого некоторые нужные низкоуровневые вещи можно сделать только через страшенную жопу (по сути — через написание своего собственного stdint с кучей ифдефов).

Без второго жить, в общем, можно, но с ним код намного нагляднее.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 2)

Чем, объективно, не устраивает C89?

Проблемы с неразвитой стандартной библиотекой?

И, почему нельзя было обойтись от GNU extensions для gcc? Неужели нельзя писать ОС на чистом C?

Про C++ - никогда, ни вкоем случае. SJW rust - тем более.

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

В C была красивая идиома - ложь как равенство нуля. Наверно, была идея как-то подойти к чему-то наподобие data-flow программированию.

Явный булев тип, как и в SQL, кстатит - всегда плохая идея, усложняющая разработку.

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

В C была красивая идиома - ложь как равенство нуля.

Что не мешало появляться функциям (даже позиксовым), возвращающим 0 как синоним успешной работы, ага. Да, это обычно означает, что ненулевой результат — код ошибки, т.е. это не синоним bool. Но там, где нужно именно да/нет, запись bool даёт чёткое понимание, о чём речь.

Явный булев тип, как и в SQL, кстати — всегда плохая идея, усложняющая разработку.

Каким образом-то?

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

Я не про возврат значения, а про то, что вместо использования в if булевых переменных как лишнего посредника, удобно использовать проверку указателя (в случае массива) на равенство нулю (nil), или проверку на равенство нулю в случае с строкой (не помню точно, -1, наверно), (тоже массив, по сути), и т.д.

https://database.guide/what-is-the-third-manifesto/

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

Проверка на месте — далеко не все случаи использования булевых переменных. Понятное дело, если просто надо проверить, не нулевой ли указатель, привлекать отдельную переменную не надо.

А вот если я пробегаюсь по массиву и должен вернуть заключение, есть ли в нём амплитуды, превышающее некоторое значение, bool это то, что доктор прописал. И тут уже становится понятно, что переменная возвращает факт наличия этих превышений, а не их количество (на что могло бы натолкнуть использование int).

hobbit ★★★★★
()

Когда уже на плюсы перейдут?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.