Страницы

Поиск по вопросам

пятница, 2 ноября 2018 г.

Могут ли функции иметь один адрес?

В ответе говорится, что 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) { }. «Склеивание» этих функций сломает код.

Комментариев нет:

Отправить комментарий