В ответе говорится, что Open Watcom компилирует такой код
bool f(bool var1)
{
bool var2 = !var1;
return var2;
}
bool g(bool var1)
{
bool var2;
if (var1) var2 = 0;
else var2 = 1;
return var2;
}
следующим образом
bool near f( bool ):
L$1:
test al,al
sete al
ret
bool near g( bool ):
jmp L$1
Т. е. из функции g
делается jmp
в начало функции f.
Получается, что у функции g
есть лишний jmp
по сравнению с f
.
Зачем это нужно и почему нельзя было просто саму функцию g
совместить с f
?
bool near f( bool ):
bool near g( bool ):
test al,al
sete al
ret
Что на эту тему говорит стандарт? Например, есть ли там пункт, что указатели на две различные функции обязаны быть различными? Если есть, то что он даёт?
На основе дискуссии здесь:
Стандарт, 5.10/2.2-3, гласит:
— Otherwise, if the pointers are both null, both point to the same function, or both represent the same address ([basic.compound]), they compare equal.
— Otherwise, the pointers compare unequal.
Компилятор имеет право, однако, сделать их равными по as-if rule, то есть, если это не влияет на видимый результат работы программы. Поэтому даже если конкретный компилятор совместил функции в отсутствие получения и сравнения их адресов, это ещё не нарушение стандарта. (Компилятор вообще имеет право выкинуть все функции, если этого никто не заметит.)
По поводу возможного практического использования этого правила.
Пусть у нас есть контейнер функций (указателей на функции) — например, std::unordered_set
— с условием уникальности. Если два независимых участка кода добавляют в него локально определённую, невидимую другим участкам кода функцию, они могут быть уверены, что функция имеет уникальный адрес и будет реально добавлена. В противном случае добавление локально определённой функции могло бы и не сработать, если в другом месте другой код добавил локальную функцию с таким же кодом.
Ещё один пример того, когда несклеивание функций полезно, из упомянутого обсуждения: SIG_IGN
и SIG_DFL
обязаны быть различными адресами. Имплементация стандартной библиотеки вполне может использовать пустые функции void ign(int) { }
и void dfl(int) { }
. «Склеивание» этих функций сломает код.
Он делает это с оптимизацией по умолчанию. Вы поспешили с вопросом - я скомпилировал тот же код с максимальной оптимизацией, и он благополучно слил функции в одну (добавил в оригинальный ответ):
Module: G:\Tmp\test.c
GROUP: 'DGROUP' CONST,CONST2,_DATA
Segment: _TEXT PARA USE32 00000009 bytes
0000 f_:
0000 g_:
0000 85 C0 test eax,eax
0002 0F 94 C0 sete al
0005 0F B6 C0 movzx eax,al
0008 C3 ret
Routine Size: 9 bytes, Routine Base: _TEXT + 0000
Подозрение, что полная оптимизация - многопроходная, а по умолчанию - проход только один. Доказать не могу :), но такая гипотеза объясняет это поведение...
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Когда импортирую через инструмент импорт, пишет что нет таблиц, либо они пустыеВозможно, кто-то сталкивался с такого рода импортом и сможет...
Есть N таблиц, N запросов: SELECT id FROM table_a WHERE value = '123', SELECT id FROM table_b WHERE value = '456', SELECT id FROM table_c WHERE value = '789', SELECT id FROM table_d WHERE value = '101112',