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)
Ответ на: комментарий от r--r--r--

Я запутался. Функции, содержащие данные больше 65КБ данных соответствуют стандарту или нет?

Про них не было утверждений.

Если нет, то какой именно пункт (требование) стандарта нарушено?

Пункт 5 Стандарта:

A strictly conforming program shall use only those features of the language and library specified in this International Standard.3) It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit.

В данном случае «shall not exceed any minimum implementation limit».

В 5.2.4.2.1 указано, что для int минимальное ограничение сверху для реализации +32767. Его строго соответствующая стандарту программа превышать не должна.

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

не соответствует стандарту именно потому, что не скомпилируется на Turbo C

А сам Turbo C соответствует стандарту?

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

Про них не было утверждений.

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

Пункт 5 Стандарта:

Хорошо, смотрим пункт 5 стандарта:

minimum implementation limit.
implementation limit.
implementation
implementation
IMPLEMENTATION

Попытка провалена.

Ещё попытки будут?

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

Ну и да,

Пункт 5 Стандарта:
A strictly conforming

На этом моменте ты потерял libc и coreutils - они не strictly conforming, так как их исходный код включает (#include) файлы, которых нет в стандартной библиотеке.

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

Хорошо, смотрим пункт 5 стандарта:

И? По-английски ты тоже не читаешь? Программа не должна выходить за минимальные пределы для реализации (то есть для компилятора, соответствующего стандарту).

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

На этом моменте ты потерял libc и coreutils - они не strictly conforming, так как их исходный код включает (#include) файлы, которых нет в стандартной библиотеке.

libc является частью реализации компилятора Си. Про coreutuls согласен, сейчас глянул исходники, он непереносимый.

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

минимальные пределы для реализации

Да, и? Я беру реализацию, с INT_MAX = 2147483647. INT_MAX выше минимальной границы по стандарту? Выше. Реализация в этом месте стандарту удовлетворяет. Программа

int i = 100'000;

Превышает лимит реализации? Нет, не превышает. Программа соответствует стандарту.

По-английски ты тоже не читаешь?

А другой язык это какой? O_о’

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

Превышает лимит реализации? Нет, не превышает. Программа соответствует стандарту.

minimum implementation limit.
MINIMUM

Она превышает минимальный лимит реализации. Указанный в 5.2.4.2.1 Стандарта.

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

Она превышает минимальный лимит реализации.

Да. Именно. ПРЕВЫШАЕТ. МИНИМАЛЬНЫЙ. Она БОЛЬШЕ ЧЕМ.

Давай опять сядем песочницу, возьмём в руки совочек и подумаем над тем, какое правило ПДД нарушает машина, которая едет ВЫШЕ установленного МИНИМАЛЬНОГО лимита скорости.

То есть, вот стоит знак «минимальная скорость 60 км.ч.». Машина едет 70. Нарушает ли машина ПДД?

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

А такой знак есть? Косвенно, наверное только знак магистрали. Раньше вроде он запрещал движение тс, у которых паспортная скорость меньше 30 или 40? Точно не помню. Могу ошибаться.

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

Давай опять сядем песочницу, возьмём в руки совочек и подумаем над тем, какое правило ПДД нарушает машина, которая едет ВЫШЕ установленного МИНИМАЛЬНОГО лимита скорости.

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

minimum implementation limit - это минимальный лимит, требуемый от реализации. То есть, любая реализация должна обеспечить для int диапазон не меньше, чем -32767..+32767, для функции обработку не менее 31 аргумента, для структуры 127 полей и т.д.

А программа должна эти минимальные лимиты не превышать.

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

5)Strictly conforming programs are intended to be maximally portable among conforming implementations. Conforming programs can depend upon nonportable features of a conforming implementation.

7 A conforming program is one that is acceptable to a conforming implementation.4)

Тебе пояснить значение артикля “a”? В данном случае это означает «[для] какой-нибудь [соответствующей стандарту реализации]».

Как бы даже printf("%zu\n", sizeof(int)); уже не strictly conforming.

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

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

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

А программа должна эти минимальные лимиты не превышать.

Хватит крутить напёрстки. Стандарт задаёт нижний диапазон значений для реализации языка. Реализация - максимальные для программы. В стандарте английским по ASCII написано, что программа не должна превышать лимиты реализации:

5.2.4.2.1 Sizes of integer types <limits.h>
...
Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
5.3.5.3.2 Characteristics of integer types <limits.h>
...
Their implementation-defined values shall be equal or greater to those shown.

Я подчёркиваю для тебя буковки "implementation-defined values". Эти values - это тот самый limit, на что ссылается

shall not exceed any minimum implementation limit.

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

r--r--r--
()
Последнее исправление: r--r--r-- (всего исправлений: 2)
Ответ на: комментарий от shdown

7 A conforming program is one that is acceptable to a conforming implementation.

Тебе пояснить значение артикля “a”?

Объясни его не мне, объясни его монку. Это он утверждает, что программа должна соответствовать вообще всем реализациям языка.

Ты в этом месте не со мной, а с ним споришь, в чём я искренне желаю тебе всяческих успехов.

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

Мне чето кажется, что на такие дороги нам вообще выезд запрещен скорее всего.

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

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

Мне чето кажется, что на такие дороги нам вообще выезд запрещен скорее всего.

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

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

Есть conforming programs

А вот это вообще странная фигня. Для него достаточно единственного Conforming implementation. Conforming implementation позволяет произвольные расширения. То есть, если я пропатчу gcc, чтобы он, встретив в первой строке слово program, трактовал весь остальной текст как программу на Паскале, то все программы на Паскале (со словом program) станут программами на Си, соответствующими стандарту?

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

минимальные лимиты для реализации языка

Так я именно это и утверждаю. Заданы minimum implementation limit. А уже strictly conforming не должен эти минимальные лимиты нарушать (чтобы работало во всех реализациях).

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

Ты сам цитируешь, что «shall not exceed any minimum implementation limit», а не максимальные для какой-то реализации.

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

Не произвольные, а неломающие.

Если расширения, то неломающие. И мой пример не ломающий. Если первым словом файла поставить program, то компилятор соответствующий стандарту вправе сообщить об ошибке компиляции.

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

А уже strictly conforming не должен эти минимальные лимиты нарушать (чтобы работало во всех реализациях).

Давай пока без "strictly". Какой пункт стандарта нарушает

int i = 100'000;

?

Ты сам цитируешь, что «shall not exceed any minimum implementation limit», а не максимальные для какой-то реализации.

У тебя (как и у всего лора) с английским (и математикой) очень печально.

"minimum implementation limit" - это гарантии от реализации на минимальные границы числового диапазона. Эти гарантии равны или больше гарантий от стандарта.

INT_MAX - это минимально гарантированное в рамках реализации максимальное значение int. Оно минимальное с точки зрения гарантий и максимальное с точки зрения возможного значения. Это гарантировано минимальный верхний предел числа. Если его попытаться превысить, гарантии корректности вычислений от реализации снимаются.

Стандарт задаёт "минимальный" == "нижний предел" максимального значения INT_MAX. Реализация может повысить этот предел.

Программа не должна превышать предел заданный как INT_MAX в конкретной реализации. Такая программа может превысить предел, указанный в тексте стандарта, если не превышает предел, заданный в конкретной реализации.

r--r--r--
()
Последнее исправление: r--r--r-- (всего исправлений: 5)
Ответ на: комментарий от monk

А вот это вообще странная фигня. Для него достаточно единственного Conforming implementation.

Кажется, ты начинаешь о чём-то догадываться…

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

«minimum implementation limit» - это гарантии от реализации на минимальные границы числового диапазона.

Нет. Это минимальные гарантии от реализации на ограничения (в том числе числового диапазона).

Смысл strictly conforming именно в том, что такая программа должна одинаково работать на любой реализации, соответствующей Стандарту.

Давай пока без «strictly».

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

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

«minimum implementation limit» - это гарантии от реализации на минимальные границы числового диапазона.

Нет. Это минимальные гарантии от реализации на ограничения

Я не понял - ты тут чему-то возражаешь или со всем соглашаешся?

Смысл strictly conforming именно в том, что такая программа должна одинаково работать

И чем ты докажешь пункт про "работать"? Я щитаю, что это твои ничем не обоснованные фантазии.

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

То есть ты сейчас утверждаешь, что "соответствующая стандарту программа - это любая программа, которую может скомпилировать хоть один соответствующая стандарту компилятор"?

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

Я не понял - ты тут чему-то возражаешь или со всем соглашаешся?

Возражаю. Ты пишешь «гарантии от (конкретной) реализации на минимальные границы диапазона», я пишу «минимальные гарантии от (любой) реализации на ограничения».

И чем ты докажешь пункт про «работать»?

«A strictly conforming program shall use only those features of the language and library specified in this International Standard. It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior.». А все реализации соответствующие стандарту должны обеспечить одинаковое поведение для всего, что в нём определено.

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

Которая не strictly conforming, а просто conforming именно такая. «A conforming program is one that is acceptable to a conforming implementation».

monk ★★★★★
()

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

Да.

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

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

Ну, давай уточним этот пункт. Если соответствующая стандарту реализация ограничивает имя файла в 12 символов, должны ли все реализации обеспечить такое поведение?

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

Если соответствующая стандарту реализация ограничивает имя файла в 12 символов, должны ли все реализации обеспечить такое поведение?

Нет. Ограничение на длину имени файла не указано в стандарте.

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

То есть размерность имени файла - это "не поведение"? Окай.

Переходим к следующей фазе торга:

#include <stdio.h>

int main(void)
{
    puts("");
    return 0;
}

Соответствует ли стандарту эта программа? Соответствует ли она строго? Является ли её "поведение" идентичным на всех совместимых со стандартом реализациях?

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

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

А зачем такое делать?

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

Чето я вообще не понял о чем вы.

О том, что в разных реализациях си на выход будет выведено разное количество байт.

В выводе нет перевода строки,

Может, всё же освежить знания перед участием в таком затяжном сраче?

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

Соответствует ли стандарту эта программа? Соответствует ли она строго? Является ли её «поведение» идентичным на всех совместимых со стандартом реализациях?

Насколько я понимаю, да.

По формулировке вопроса могу предположить, что ты считаешь по-другому. Где не идентично?

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

О том, что в разных реализациях си на выход будет выведено разное количество байт.

Это не считается выводом программы, стандарт не касается the mechanism by which output data are transformed after being produced by a C program. Выводом данной программы считается newline character.

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

Окей, но за вывод все-равно отвечает операционная система. Это вопросы на грани Си и операционной системы.

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

Это не считается выводом программы,

Я искренне восхищаюсь твоей способностью к двоемыслию.

Выводом данной программы считается newline character.

И тут ты на полном ходу влетаешь в

5.3
Environmental considerations
5.3.1
Character sets
Two sets of characters and their associated collating sequences shall be defined: the set in which source
files are written (the source character set), and the set interpreted in the execution environment (the
execution character set). Each set is further divided into a basic character set, whose contents are given
by this subclause, and a set of zero or more locale-specific members (which are not members of the
basic character set) called extended characters. The combined set is also called the extended character
set. The values of the members of the execution character set are implementation-defined.

Подчёркиваю для тебя последнюю строчку:

The values of the members of the execution character set are implementation-defined.

Это значит, что "new line character", как и любой другой "character" - implementation-defined.

А это в твоей интерпретации стандарта означает, что они не могут быть использованы в

A strictly conforming program shall use only those features of the language and library specified in this International Standard.3) It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior,

Таким образом ты исключил из " strictly conforming program" даже простейший "hello world".

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

Я искренне восхищаюсь твоей способностью к двоемыслию.

Мне нравится ваш спор. Вы спорите об интерпретации текста, написанного и переписанного несколькими поколениями отборных наркоманов и аутистов. Без шуток, Ритчи сотоварищи траву дули – паровоз позавидует, а про аутизм говорить вообще излишне. Неудивительно, что там разные части могут противоречить друг другу, не сходиться, допускать двойную (или даже пятерную) интерпретацию или просто что-то упускать.

Классический вопрос:

struct {
  int a;
  char c;
  double d;
} s;

memset(&s, 0, sizeof(s));

Будет ли здесь обнулён паддинг? Варианты ответов:

  1. Да
  2. Нет
  3. Зависит
  4. Пшёл нах

Правильными являются все 4 сразу. Туда же идут темы про pointer provenance, про которое в стандарте упомянуто, но не упомянуто что это вообще такие и какие именно выдвигаются требования. И так далее и тому подобное. Пытаться понять, что же именно «имел ввиду автор» в случае с Сишечкой абсолютно бессмысленно, стандарт ближе к религиозным текстам по содержимому чем к собственно формальным документам, и интерпретировать его стоит аналогично. Т.е. ориентироваться на позицию верховных жрецов^W^Wразрабов компиляторов, а не то может прилететь.

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

Вы спорите об интерпретации текста, написанного и переписанного несколькими поколениями

Всё так. Но тут спор идёт между желанием увидеть в буквах подтверждение своей хотелки, благо, что одна неосторожная формулировка позволяет попытаться натянуть сову, и фактическим положением вещей. Юмор в том, что сова, натягиваясь на одну формулировку, рвётся в клочья в 100500 других местах, и я развлекаюсь тем, что перебираю эти дырки.

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

Доводишь бедного монка. Спор уже давно не технический. Я смотрю за вами, ужасаюсь. К стандарту конечно надо стремиться, но не доводить свое стремление до абсурда.

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

Спор уже давно не технический.

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

Доводишь бедного монка.

Тащем-та, я иллюстрирую ему логические выводы из принятого им тезиса.

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

К стандарту конечно надо стремиться, но не доводить свое стремление до абсурда.

Стандарт нужно переписать человеческим языком. Но на это, конечно же, никто не пойдёт, проще Rust взять.

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

Это значит, что «new line character», как и любой другой «character» - implementation-defined.

Нет. Это значит только то, что написано: какие именно символы в целом в execution character set определяется реализацией.

Но в следующем пункте определяются обязательные члены этого набора: 26 заглавных букв, 26 строчных букв, 10 цифр, 29 знаков …

Конкретно про «new line character»:

In the basic execution character set, there shall be control characters representing alert, backspace, carriage return, and new line.

Таким образом ты исключил из " strictly conforming program" даже простейший «hello world».

Вывод «hello world» является " strictly conforming program". Вывод «привет мир» не является.

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

в следующем пункте определяются обязательные члены этого набора

Но не их численное представление.

Конкретно про «new line character»:

Но ты же не дочитал дальше:

5.3.3 Character display semantics
...
Each of these escape sequences shall produce a unique implementation-defined value which can be
stored in a single char object. 

Я опять заостряю твоё внимание на формулировке "implementation-defined value".

Теперь тебе предстоит объяснить:

  1. почему использование в коде этого значения не является "implementation-defined behavior", хотя его значение является "implementation-defined value"?
  2. почему использование "implementation-defined" INT_MAX будет нарушением, а использование "implementation-defined" численного значения для "new line character" - не будет?
r--r--r--
()
Ответ на: комментарий от r--r--r--

Но не их численное представление.

Вот его использовать нельзя. Код типа

char s[] = {'H', 'e', 'l', 10};

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

почему использование в коде этого значения не является «implementation-defined behavior», хотя его значение является «implementation-defined value»?

Потому что поведение программы от него не зависит.

почему использование «implementation-defined» INT_MAX будет нарушением, а использование «implementation-defined» численного значения для «new line character» - не будет?

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

Например

int i;
if(INT_MAX > 100000) {
  i = 40000 + 60000;
  printf("%i", i);
} else {
  printf("%s", "100000");
}
monk ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.