Программистские задачки и хитрости

Аватара пользователя
MX_Master
Мастер
Сообщения: 7476
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3099
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Кстати, а насколько медленней операции с 64-битными числами по сравнению с 32-битными? На 32-битном процессоре.
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

MX_Master писал(а):насколько медленней операции с 64-битными числами по сравнению с 32-битными? На 32-битном процессоре.
От системы команд зависит. И от реализации этих операций в языках. Конкретно по Cortex'ам не в курсе. Но обычно пересылка-сложение-вычитание раза в 2-3 медленнее. Собственно, проверить нетрудно.
Чудес не бывает. Бывают фокусы.
Аватара пользователя
MX_Master
Мастер
Сообщения: 7476
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3099
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Спасибо всем за советы. Оптимизирую прошивку сопроцессора (arisc, Allwinner H3) в ближайшее время.
Есть ещё один теоретический вопрос, на этот раз про аппаратные UART'ы. Насколько я знаю, выходную частоту у этих аппаратных модулей можно довольно гибко менять. Допустим, в микроконтроллере есть ряд аппаратных UART'ов, которые никак не используются. Можно ли (в теории) с помощью аппаратных TX пинов выводить шаги на частотах от 1 до 200000 Гц? :)
Аватара пользователя
Argon-11
Мастер
Сообщения: 2067
Зарегистрирован: 07 июн 2017, 17:48
Репутация: 461
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Argon-11 »

Не знаю, как в H3, но я в одном девайсе на PIC через UART реализовал вывод звука на бипер. Грубо говоря, меандр с произвольной частотой.
Сергей Саныч писал(а):longtick += curtick - prevtick; // Разность текущего и предыдущего отсчетов прибавим к 64-битному счетчику
Давно программизмом не занимался, не могу сходу въехать - не опасно ли вычитание двух беззнаковых? Особенно после переполнения, когда prevtick > curtick. Какой при этом результат будет?
Александр Д
Кандидат
Сообщения: 49
Зарегистрирован: 27 дек 2017, 10:42
Репутация: 6
Настоящее имя: Александр
Откуда: Брянская область
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Александр Д »

MX_Master писал(а): Можно ли (в теории) с помощью аппаратных TX пинов выводить шаги на частотах от 1 до 200000 Гц? :)
да, но:
1. зависит от наличия в МК, в самом аппаратном модуле uart, буфера передатчика. Например, в младший АВР он всего (или целых - как посмотреть) два байта. И тут вам решать: или через прерывания опустошения этого буфера выдавать в него очередные байты (если нужны, конечно), или через цикл гнать нужную последовательность байт
2. Вы выдали 10101010, а uart САМ добавить Стартовый бит в начало, Стоповый - в конец. Если не отключили в настройках, то еще может добавить бит (или 2) четности...
поэтому вы обязаны понимать, что ваша 10101010 превратится в 1101010101 или примерно такое...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

Argon-11 писал(а):Давно программизмом не занимался, не могу сходу въехать - не опасно ли вычитание двух беззнаковых? Особенно после переполнения, когда prevtick > curtick. Какой при этом результат будет?
Нормальный результат будет :) Переполнение счетчика компенсируется переполнением при вычитании. Re: Программистские задачки и хитрости #38
Вот еще пример. Для наглядности переменные возьмем покороче, 4-битные.

Код: Выделить всё

 0001 (curtick=1)
-
 1110 (prevtick=14)
=
 0011 (curtick-prevtick=3)
Чудес не бывает. Бывают фокусы.
Аватара пользователя
Argon-11
Мастер
Сообщения: 2067
Зарегистрирован: 07 июн 2017, 17:48
Репутация: 461
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Argon-11 »

Александр Д писал(а): ваша 10101010 превратится в 1101010101 или примерно такое...
если учесть, что старт-бит обычно это '0', а стоп-бит - '1', то 10101010 превратится в 0101010101, что в общем-то не хуже :)
Сергей Саныч писал(а):возьмем покороче, 4-битные.
Короче, 5-летний перерыв может начисто стереть из памяти правила двоичного вычитания :)
Аватара пользователя
MX_Master
Мастер
Сообщения: 7476
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3099
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Argon-11 писал(а):если учесть, что старт-бит обычно это '0', а стоп-бит - '1', то 10101010 превратится в 0101010101, что в общем-то не хуже
А ведь множителей частоты может быть и больше. К тому же битрейт тоже настраивается. А для продолжительного постоянного вывода можно прикрутить DMA. Надо попробовать на досуге.

Пример

Код: Выделить всё

0000000001 0000000001 0000000001 0000000001 - 4 шага (х1)
0000100001 0000100001 0000100001 0000100001 - 8 шагов (х2)
0001001001 0001001001 0001001001 0001001001 - 12 шагов (х3)
0101010101 0101010101 0101010101 0101010101 - 16 шагов (х4)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

MX_Master писал(а):Можно ли (в теории) с помощью аппаратных TX пинов выводить шаги на частотах от 1 до 200000 Гц?
Оглядываясь на стоимость МК считаю это извратом! :) Хотя если ваше время как программиста ещё дешевле, то почему-бы и нет... :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Argon-11
Мастер
Сообщения: 2067
Зарегистрирован: 07 июн 2017, 17:48
Репутация: 461
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Argon-11 »

MX_Master писал(а):А ведь множителей частоты может быть и больше.
Александр Д не битрейт имел ввиду, а что якобы есть риск получить неровную импульсную последовательность с двумя подряд идущими единицами.
MX_Master писал(а):Надо попробовать на досуге.
Не пробуй. Делай. Или не делай. Не пробуй. (c) Йода :)

Скорее всего работать будет, но с нюансами. Например, как на лету менять битрейт (поди еще и без прерываний)? Как задавать кол-во выдаваемых импульсов?
Наверное, все решаемо. Видимо, все параметры должны задаваться в одном сервоцикле и в его пределах быть постоянными?
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Argon-11 писал(а):Например, как на лету менять битрейт (поди еще и без прерываний)?
Перенастройка порта довольно длительная операция во время которой передача невозможна.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 7476
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3099
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

UAVpilot писал(а):Перенастройка порта довольно длительная операция во время которой передача невозможна.
Вот о таких нюансах я и спрашивал (: У аппаратного таймера перенастройка проходит быстро. Лично замерял. А про аппаратные UART'ы таких данных не имею.
UAVpilot писал(а):Оглядываясь на стоимость МК считаю это извратом!
В какой-то степени, дёргать пины в прерываниях на больших частотах довольно странно. Впрочем, как и юзать DMA в роли счётчика шагов :)
Александр Д
Кандидат
Сообщения: 49
Зарегистрирован: 27 дек 2017, 10:42
Репутация: 6
Настоящее имя: Александр
Откуда: Брянская область
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Александр Д »

любой опытный и адекватный программер всегда вынужден быть немножечко извращенцем ))) ибо ровно бывает крайне редко! ))
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

MX_Master писал(а):А про аппаратные UART'ы таких данных не имею.
Насколько помню, PC-шные UART перестраиваются без задержек. А вот у STM только через Disable-Enable.
Но UART плоховато подходит для выдачи произвольной последовательности, именно из-за старт-стопной передачи. В этом плане лучше SPI. Но не менять битрейт на ходу, а транслировать заранее определенную (или вычисленную) последовательность из буфера посредством DMA.
Чудес не бывает. Бывают фокусы.
Alex_kh
Мастер
Сообщения: 362
Зарегистрирован: 03 сен 2019, 01:31
Репутация: 37
Настоящее имя: Александр
Откуда: Харьков
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Alex_kh »

USVpilot а jsr -(pc) это не та самая которая потом называлась "чайку попить", название то запомнилось, а вот мануалы рыть..
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Вроде не встречал такого названия...
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
netraider
Мастер
Сообщения: 209
Зарегистрирован: 23 май 2015, 10:47
Репутация: 49
Настоящее имя: Юрий
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение netraider »

UAVpilot писал(а):Ладно, это было легко гугить. :)

Вот ещё:

Код: Выделить всё

$ cat t.c
#include <stdio.h>

void print(int a, int b) {
	printf("print: a=%d, b=%d\n", a), b;
}

void main(void) {
	int x = 5, y = 8;

	print(x, y);
}
$ make t
cc     t.c   -o t
$ ./t
print: a=5, b=8
$ 
Где ошибка и почему работает? :)
Наблюдаемое "верное" поведение является частным случаем классического неопределенного поведения. Любые попытки "доказательства корректности" с помощью компилятора в этом случае не имеют смысла. Компилятор имеет право даже не компилировать этот код.
7.21.6.3 The printf function
2) The printf function is equivalent to fprintf with the argument stdout interposed before the arguments to printf
7.21.6.1 The fprintf function
2) The fprintf function writes output to the stream pointed to bystream, under control of the string pointed to by format that specifies how subsequent arguments are converted for output. If there are insufficient arguments for the format, the behavior is undefined. <---
PS: Раз тут был упомянут gcc: при отсутствии флага -ffreestanding возвращаемый тип функции main должен быть 'int'.
--
At the nanometer level, the world is made of rubber (с)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

В данном случае поведение вполне ожидаемое, более того, такой-же набор машинных инструкций сгенерит и сам компилятор из "правильного "текста при некоторых режимах оптимизации.
И с возвращаемым типом всё правильно.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
netraider
Мастер
Сообщения: 209
Зарегистрирован: 23 май 2015, 10:47
Репутация: 49
Настоящее имя: Юрий
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение netraider »

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

Стандарт языка не дает никаких гарантий при нарушений правил, касающихся неопределенно поведения. Но он гарантирует одинаковое поведение программ, скомпилированных на conforming implementations при отсутствии UB.

Механизм передачи аргументов - он не один, их существует несколько. Что-то применяется чаще всего, что-то реже. Какие-нибудь агрессивные оптимизации могут приводить к передаче аргументов через регистры или как-то иначе. Конкретно в случае с printf у разработчиков компилятора руки немного связаны тем, что они в какой-то степени поддерживают общеиспользуемый ABI. Т.е. ожидать здесь сильно различающегося поведения не приходится. Но вот в случае с user-defined функциями с эллипсисом все не так однозначно. В более сложной программе собственный "аналог" 'printf' может вести себя иначе. Но в любом случае это все спекуляции.
более того, такой-же набор машинных инструкций сгенерит и сам компилятор из "правильного "текста при некоторых режимах оптимизации
Ключевой момент - "при некоторых режимах оптимизации". А при некоторых - нет. Выкинет 'b', как неиспользуемую с т.з. языка переменную и будет прав, т.к. стандарт дает ему на это право:
5.1.2.3/4
In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced.
Что собственно и делают большинство компиляторов (в т.ч. и gcc 9.2). Какой либо связи между ‘b’ и тем фактом что ‘printf’ что-то там читает из некоторой области памяти (совершенно неважно откуда именно, хоть стек, хоть регистры), которая содержит значение 'b' с точки зрения стандарта нет. Соответственно ни о каких side эффектах говорить не приходится, хотя вызов ‘printf’ обеспечивает их, но только для явно переданных аргументов.

Но вот наблюдаемое поведение при такой оптимизации изменится. И единственный правильный ответ на исходный вопрос - пример содержит неопределенное поведение. О чем явно и говорит стандарт языка.

Еще один, в некоторой степени похожий пример:

Код: Выделить всё

#include <stdio.h>

int main()
{
    int* a;
    int* b;
    int c = (int)(a > b);
    printf("%d", c);
}
Что будет напечатано в результате выполнения? В 99% случаев что-то будет напечатано, можно даже "утверждать" что именно, зная детали реализации.
Но на некоторых процессорах выполнение может привести к падению. Некоторые процессоры могут использовать для хранения адресов специальные адресные регистры и значения этих регистров проверяются при загрузке в них данных (значений указателей). Неинициализированное значение, а точнее содержащее undefined value может представлять из себя trap representaion. Или например(!) процессор может выполнять проверку доступности сегмента в схеме segment-offset.

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

Далее: если попытаться написать свой аналог ‘printf’ с эллипсисом, где спецификатору ‘%d’ будет также соответствовать тип ‘int’, то при отсутствии аргумента будет выполнена попытка чтения из области памяти, которая не является областью памяти, где изначально находилось значение типа ‘int’. Это очень сильно похоже на вышеописанный пример со сравнением указателей. Для знаковых скалярных типов тоже могут существовать значения, которые являются trap representation (но для беззнаковых это не так). К сожаленью (или к счастью) такие архитектуры являются очень редкими, поэтому воочию убедиться в этом весьма затруднительно. Но это не отменяет факта их существования.

Стандарт просто определяет перечень легальных способов 'создания' значений некоторого типа (‘int’ в данном случае, или значений указателей). Попытка чтения значений, которые были созданы каким-либо иным способом или интерпретация области памяти как области памяти, которая содержит объект другого типа (здесь есть некоторые нюансы, я пока про ‘int’ и указатели) - приводит к неопределенному поведению. Это как раз и является одним из факторов, который позволяет использовать язык С на разных экзотических архитектурах.

Ну и совсем классический пример, который более пригоден для иллюстрации неопределенного поведения, поскольку "наблюдаемый" результат не совсем очевиден:

Код: Выделить всё

#include <stdio.h>

int main()
{
    int i = 5; 
    i = ++i + ++i;
    printf("%d", i);
}
И с возвращаемым типом всё правильно
Увы нет. Для того, чтобы сделать такое заключение нужны критерии "правильности".
Вот эта функция "правильная" или нет? (риторический вопрос)

Код: Выделить всё

int plus(int a, int b)
{
    return a - b;
}
Интуитивно кажется, что нет. Может быть следующий вариант правильный?

Код: Выделить всё

int plus(int a, int b)
{
    return a + b;
}
Но можно утверждать, что и этот вариант неправильный. Поскольку исправлять нужно название функции:

Код: Выделить всё

int minus(int a, int b)
{
    return a - b;
}
Оба варианта могут быть правильными. Все зависит от спецификации (которая здесь отсутствует).

Тоже самое и с ‘main’. Но в этом случае спецификация есть - это стандарт языка. И ни как не компилятор. Более того - стандарт в т.ч. описывает и требования, предъявляемые к компиляторам.

Стандарт определяет две conforming implementation: freestanding и hosted. Первая - это такая 'урезанная' версия для платформ на которой сам компилятор не может быть запущен (в общем случае). Микроконтроллеры, embedded, части ядра и т.п. В частности freestanding реализация не обязана поддерживать все библиотечные функции, которые определены в стандарте.

Вторая - hosted версия, это "полноценная" реализация, которая используется в подавляющем большинстве случаев для прикладных программ. Также в стандарте определены две версии сред выполнения, которые называются аналогично: freestanding и hosted.

Для freestanding в отношении ‘main’ стандарт разрешает все что угодно:
5.1.2.1/1
In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.
5.1.2.1/2
The effect of program termination in a freestanding environment is implementation-defined.
(но с оговоркой что все должно быть задокументировано, см. ниже)

А вот к hosted environment требования совершенно другие:
5.1.2.2.1/1

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of 'int' and with no parameters:

int main(void) { /*...*/ }

or with two parameters [...]:

int main(int argc, char *argv[]) { /*...*/ }

or equivalent, or in some other implementation-defined manner.
И существует два лагеря людей, которые по разному понимают этот параграф:

Первые утверждают что тип возвращаемого значения безоговорочно 'shall be defined with a return type of 'int' (причем значение слова 'shall' в стандарте оговаривается отдельно, как самое сильное требование, нарушение которого приводит к UB(параграфы 4/1, 4/2). И при этом последняя часть - 'or in some other implementation-defined manner' относится к дополнительным параметрам ‘main’, вроде такого:

Код: Выделить всё

int main (int argc, char *argv[], char *env[])
Второй лагерь утверждает что hosted реализация может использовать любые сигнатуры для ‘main’, в т.ч. и ‘void main()’.

Если с первым вариантом все понятно - нельзя и все, то второй переносит ответственность на реализацию.

Что из этого следует: во первых - любое использование implementation-defined аспектов компилятора выводит программу из категории 'strictly conforming program' (параграф 5/4) и она сразу становится зависимой от конкретного компилятора и опционально от флагов компиляции.

'strictly conforming program' - это весьма жесткое ограничение, но следствием является тот факт, что такие программы являются наиболее переносимыми между компиляторами, т.к. не зависят от implementation-defined. Поэтому любой пример кода, в котором явно дополнительно не указан компилятор и ключи компиляции (именно таким был исходный пример), я рассматриваю как strictly conforming program.

Во вторых - нужно принимать во внимание еще один пункт стандарта - 5/8:
An implementation shall be accompanied by a document that defines all implementation-defined and locale-specific characteristics
И у GCC такой документ есть. https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc.pdf

Там в частности описан поддерживаемый список языков и версий стандартов.
Нас интересует ISO/IEC 9899:2018 поскольку именно он является текущим стандартом языка С (а стандарт используемый в примере не был указан). Для текущего стандарта нужен ключ '-std=iso9899:2017'

Далее:
By default, GCC provides some extensions to the C language that, on rare occasions conflict with the C standard. See Chapter 6 [Extensions to the C Language Family], page 451. Some features that are part of the C99 standard are accepted as extensions in C90 mode, and some features that are part of the C11 standard are accepted as extensions in C90 and C99 modes. Use of the ‘-std’ options listed above disables these extensions where they conflict with the C standard version selected.
Ключ ‘-std’ отключает использование extensions. На упомянутой странице 451 в Chapter 6 имеется следующее:
GNU C provides several language features not found in ISO standard C. (The ‘-pedantic’ option directs GCC to print a warning message if any of these features is used.)
Если попытаться откомпилировать ‘void main(){}’ с ключем '-pedantic', то возникает следующее предупреждение:
<source>:3:6: warning: return type of 'main' is not 'int' [-Wmain]
Что это значит? А это значит, что такая language feature not found in ISO standard C.

Таким образом GCC не только не разрешает явное использование ‘void main()’, но и явно указывает на то, что такая возможность не совместима со стандартом языка.

Более того, в этом же документе можно найти и другие подтверждения этому:
The standard also defines two environments for programs, a freestanding environment, required of all implementations and which may not have library facilities beyond those required of freestanding implementations, where the handling of program startup and termination are implementation-defined; and a hosted environment, which is not required, in which all the library facilities are provided and startup is through a function

int main(void)
or
int main (int, char *[]).

An OS kernel is an example of a program runningin a freestanding environment; a program using the facilities of an operating system is an example of a program running in a hosted environment. GCC aims towards being usable as a conforming freestanding implementation, or as the compiler for a conforming hosted implementation. By default, it acts as the compiler for a hosted implementation.
Плюс здесь указан тот факт, что по умолчанию используется hosted implementation, а не freestanding (что абсолютно логично).

Помимо этого в описании опции '-Wmain' указано следующее:
Warn if the type of main is suspicious. main should be a function with external linkage, returning int, taking either zero arguments, two, or three arguments of appropriate types. This warning is enabled by default in C++ and is enabled by either ‘-Wall’ or ‘-Wpedantic’.
Т.е. разработчики GCC явно принадлежат к той категории, которая трактуют несколько неоднозначную фразу из параграфа стандарта 5.1.2.2.1/1 как явный запрет 'void' в качестве возвращаемого типа.

Соглашаться в контексте всего этого с фразой "с возвращаемым типом всё правильно" я определенно не могу. "Правильно" может быть в соответствии с чем-то. 'void main' в случае с gcc - это "не правильно" в соответствии со стандартом языка (и, косвенно, в соответствии с документом от GCC, который требуется, опять же - по стандарту языка). Совершенно не имеет значения тот факт, что при некоторых флагах компилятора это "работает", компиляторы вынуждены много чего поддерживать для legacy кода.
--
At the nanometer level, the world is made of rubber (с)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Много умных слов - это круто, но к данному примеру никакого отношения не имеет, ибо в нём ни о каких опциях gcc не говорится, т.е. используем gcc "по дефолту". Иначе вообще ни очём говорить не стоит, ибо этими опциями можно добиваться совершенно противоположных результатов - таков gcc.
Касательно примера повторю: не смотря на якобы синтаксическую ошибку gcc и множество других компиляторов С сгенерят совершенно законный и рабочий код.
Некоторые режимы оптимизации - это например оптимизация по скорости, по размеру кода и т.п. И большинство их сгенерят аналогичный код.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Ответить

Вернуться в «Оффтоп»