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

341
26 января 2017, 02:51

В ответе говорится, что 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         
  • Что на эту тему говорит стандарт? Например, есть ли там пункт, что указатели на две различные функции обязаны быть различными? Если есть, то что он даёт?

  • Какие плюсы от такой реализации?
Answer 1

На основе дискуссии здесь:

Нет, адреса не должны быть равными

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

Answer 2

Он делает это с оптимизацией по умолчанию. Вы поспешили с вопросом - я скомпилировал тот же код с максимальной оптимизацией, и он благополучно слил функции в одну (добавил в оригинальный ответ):

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

Подозрение, что полная оптимизация - многопроходная, а по умолчанию - проход только один. Доказать не могу :), но такая гипотеза объясняет это поведение...

READ ALSO
Как импортировать Sakila Database в phpMyAdmin?

Как импортировать Sakila Database в phpMyAdmin?

Когда импортирую через инструмент импорт, пишет что нет таблиц, либо они пустыеВозможно, кто-то сталкивался с такого рода импортом и сможет...

303
MYSQL - получить одинаковые значения из n запросов

MYSQL - получить одинаковые значения из n запросов

Есть 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',

357
PyQt MySql driver not loaded

PyQt MySql driver not loaded

Использую PyQt v 54

462