LINUX.ORG.RU

На первые 4 вопроса ответил из соображений x86/amd64 сишки. Дошел до последнего, осознал подвох. 5/5. В общем, вся суть язычка-макропроцессора над ассемблером — стандарт описывает лишь синтаксис. Весь рантайм — Undefined Behavior, Unspecified Behavior, and Implementation Speciifc.

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

На первые 4 вопроса ответил из соображений x86/amd64 сишки.

Я отвечал сразу как написано в стандарте. Но я думал, что тест ждёт от меня чтобы я ответил, из соображений gcc amd64, и думал что за днища составляли тест.

Удивился, когда в итоге получил 5/5, поэтому решил поделиться на лоре.

fsb4000 ★★★★★
() автор топика

0 очков. Я рад, что стандарт не нужен и потому я знаю поведение компиляторов, а не закорючки из комитетской макулатуры. Например, к слову о последнем вопросе:

https://gcc.godbolt.org/z/zEEjoo81o

Я правильно угадал, что будет 2, это не UB в большинстве компиляторов. Вот нарушение strict aliasing — это настоящее UB, про которое нужно помнить, но ровно для того, чтобы не забыть прописать "-fno-strict-aliasing" в опциях компиляции, после чего выкинуть стандарт в мусорник и больше в него не смотреть.

byko3y ★★★★
()

4 вопроса на одно и то же это «сильно»

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

clang предупреждает об этом, даже без -Wчто-нибудь: https://gcc.godbolt.org/z/1n4dedq77

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

byko3y ★★★★
()

Тест десять из десяти

Aswed ★★★★★
()

Как я могу знать его стандарт, если я учил С по книжке 1988 года (переведено до принятия перового стандарта ANSI C)???

the size of the char type itself is not specified in bits either.

Ну я лох... Привык, что char и int одинаковые.

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

чтобы не забыть прописать "-fno-strict-aliasing" в опциях компиляции, после чего выкинуть стандарт в мусорник и больше в него не смотреть.

Программа получится сильно завязанной на gcc.

praseodim ★★★★★
()

Ну, вот ты такой умный, а я языки плохо знаю. Вот объясни мне по-русски, как в последнем примере может получиться не 2 и с какого перепугу там undefined behavior. Есть совершенно чёткий приоритет арфиметических операций. Прописанный ещё в с89 или ещё раньше. Эту таблицу студентиков зубрить заставляют, чего они не делают. Сначала выполняется i++, возвращает 0. Потом ++i, возращает 2. Потом +. Итог 2. Иначе быть не может. Только если в багованных компиляторах. Но если писать код, расчитанный на них, можно рехнуться. Конечно, такой код писать нельзя, это называется труднопонимаемые трудночитаемые приёмы. Но тем не менее.

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

это не UB

Нет, это ты не знаешь, что такое UB.

И самое главное — нахрена эти извращения? Кому вообще в реальности хоть раз понадобилось исполнять что-то типа i++ + ++i?

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

Я для этого даже написал регулярку, которая находит присваивания в условных выражениях

вы изобрели линтер. поздраляем!

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

я знаю поведение компиляторов

Я правильно угадал, что будет 2

/0

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

Тут не вопрос приоритета арифметических операций, строго говоря она тут вообще одна — сложение. В С и С++ порядок вычисления операндов (равно как и аргументов функции) отдан на откуп компилятору. Возможно более наглядно:

void foo(int a, int b) {
  print(a, b);
}

...
int x = 0;
foo(++x, ++x);
...

Оно может напечатать как 1,2 так и 2,1.

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

Много буков. Согласно стандарту языка, результат должен быть 12, однозначно. Те компиляторы, которые выдают не 12 - багованы. Ещё раз, такой код писать нельзя, тем не менее, неоднозначности тут нет.

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

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

Чё? Операций тут 3. ++до_переменной, ++после переменной, +. У них совершенно чёткий приоритет. Распечатай себе эту таблицу и заучи, если хочешь читать код от }{@керов без словаря.

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

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

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

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

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

Это всё не важно. С т. з. компилятора выполнение нескольких разных операций над одной сущностью в одной строке – компилятороспецифично.

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

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

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

Нет, не знаю. 0 из 5. И мне хорошо, чувствую себя прекрасно.

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

0 очков. Я рад, что стандарт не нужен и потому я знаю поведение компиляторов, а не закорючки из комитетской макулатуры.

Ну а теперь скажи не подглядывая, какой результат выдаст gcc для

#include <stdio.h>

int main() {
	unsigned x = 0xFFFFFFFF;
	int v = 32;
	printf("%u\n", x >> v);
}
AlexVR ★★★★★
()
Ответ на: комментарий от lenin386

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

там же написано. int может быть 2 байта, а не 4 как мы сейчас привыкли.

Если заменить в том примере 16 на 32, чтобы проверить с текущем размером int, то результат легко может быть не 1.

Вот смотри что сделал clang 13: https://gcc.godbolt.org/z/n6h5TcE88

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

Оно может напечатать как 1,2 так и 2,1.

Может. Но напечатает 2,2. И это совершенно правильно и однозначно. У префиксного ++ приоритет перед вызовом функции. Поэтому, сначала считаются два ++, потом результат кладётся на стек дважды.

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

там же написано. int может быть 2 байта,

Может. И ч0?

 int i = 16
(((((i >= i) << i) >> i) <= i));

Считаем по слогам.

(i >= i) = 1
1<<i = 2
2>>i = 0
0<=i = 1
1

Где тут неоднозначность? Какие такие 16 бит нахен?

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

Где тут неоднозначность? Такие 16 бит нахен?

1<< 16 = 2

Вот тут у тебя ошибка.

1 << 16 = или UB, если int два байта, или 65536

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

В этом примере - конечно, не о приоритете операций. Я вообще с трудом представляю, где тут может получиться подвох.

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

Может. Но напечатает 2,2.

Ты попробовал? У меня вот clang 1,2 напечатал.

И это совершенно правильно и однозначно. У префиксного ++ приоритет перед вызовом функции. Поэтому, сначала считаются два ++, потом результат кладётся на стек дважды.

У тебя невероятная каша в голове. Еще ты забавно аппелируешь к стандарту парой сообщений выше. Было бы интересно почитать выдержку из него (hint: не одним приоритетом операторов едины).

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

С хера ли 1<<16? 1<<1. В передыдущей итарции у нас результат 1. Тут скобочки, товарищ!

(i >= i) это просто сравнение. Оно не меняет значение i.

(16 >= 16) == 1, i по-прежнему 16…

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

Я для этого даже написал регулярку, которая находит присваивания в условных выражениях.

gcc же и так выдает предупреждение.

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

Где тут неоднозначность?

Этот пример исходит из того, что sizeof(int) может быть 16. Поменяй на 32 и разбей вычисление выражения:

#include <stdio.h>

int main() {
	int i = 32;
	int a = i >= i;
	int b = a << i;
	int c = c >> i;
	int d = c <= i;

	printf("%d %d %d %d\n", a, b, c, d);
}

Проверяем:

❯ gcc test9.c && ./a.out 
1 1 0 1
❯ gcc -O2 test9.c && ./a.out 
1 0 0 1
❯ clang test9.c && ./a.out 
test9.c:5:12: warning: self-comparison always evaluates to true [-Wtautological-compare]
        int a = i >= i;
                  ^
1 warning generated.
1 1 490651152 0

❯ ./a.out 
1 1 -2026177264 1

❯ ./a.out 
1 1 211988912 0
❯ clang -O2 test9.c && ./a.out 
test9.c:5:12: warning: self-comparison always evaluates to true [-Wtautological-compare]
        int a = i >= i;
                  ^
1 warning generated.
1 -468013512 0 1

❯ ./a.out 
1 -1474775704 0 1

❯ ./a.out 
1 1560682904 0 1
AlexVR ★★★★★
()
Ответ на: комментарий от lenin386

Вроде для 16-и битных платформ gcc не бывает.

С чего бы это? Даже avr-gcc бывает.

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

Согласно стандарту языка, результат должен быть 12, однозначно.

Перечитывай стандарт языка значит. Или хотя бы осиль «много букв» (там не так уж и много на самом деле, можно детали скипать).

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

А чего тут может быть кроме нуля-то?

Этот пример строится на том, что int может быть 16-битным (AVR, маленький RISC-V, …). А сдвиг на число бит - это UB. На «обычной» машинке, это значит, что xFFFFFFFF >> 32 уже нельзя. И очень обидно это увидеть в первый раз. Протестируй код А вы знаете стандарт С? (комментарий) с и без оптимизацией.

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

В последнем примере вообще эталонный UB. Прямо энциклопедический, с которого и стоит начинать знакомство с UB.

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

Нет. Писать надо универсальный код, если компилятор тоже не ты пишешь. Завтра разрабу компилятора в голову другое понимание стандарта придёт и ты будешь всё в лихорадке переписывать, возможно когда у тебя ракета упадёт.

peregrine ★★★★★
()

Не очень понимаю, а что вы хотите от «относительно кроссплатформенного ассемблера»?

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

Где там UB? С четвертым примером я ошибся, согласен. Там действительно ньюанс с 16-битным кодом будет. Но 5-й совершенно чётко в приоритеты операций раскладывается.

lenin386 ★★★★
()
Последнее исправление: lenin386 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.