Подтвердить что ты не робот

Какие платформы имеют несовместимые ABI для C и С++?

Только что я пришел к выводу, что стандарт С++ говорит, что функции C и С++ имеют разные и несовместимые типы, даже если их сигнатуры типов одинаковы (подробнее см. this вопрос). Это означает, что вам технически не разрешено передавать С++-функцию функции C, например pthread_create().

Мне любопытно, есть ли какие-либо используемые платформы, где два ABI на самом деле отличаются (помимо очевидных отличий от названия). В частности, знает ли кто-нибудь о каких-либо платформах, на которых эта программа на С++ не сможет скомпилировать и запустить?

#include <assert.h>

extern "C" int run(int (*f)(int), int x) { return f(x); }

int times2(int x) { return x * 2; }

int main(int argc, char *argv[]) {
  int a = times2(argc);
  // This is undefined behavior according to C++ because I am passing an
  // "extern C++" function pointer to an "extern C" function.
  int b = run(&times2, argc);
  assert(a == b);
  return a;
}
4b9b3361

Ответ 1

Я не знаю каких-либо платформ, где ABI отличается, но даже если соглашения о вызовах на C и С++ одинаковы, стандарт С++ требует, чтобы компилятор выдавал диагностику для этой программы. Связывание с указателем на функцию-с-языком C - это другой тип привязки к указателю на функцию-с-С++, поэтому вы должны иметь возможность перегружать run() следующим образом:

extern "C" int run(int (*f)(int), int x) { return f(x); }
extern "C++" int run(int (*f)(int), int x) { return f(x); }

Теперь, когда вы вызываете run(times), он должен вызывать второй, поэтому следует, что первый из них не является вызываемым (отсутствует преобразование из указателя-в-функцию-с-C-language-linkage в указатель- to-function-with-С++ - language-linkage), поэтому исходный код должен вызвать диагностику компилятора. Большинство компиляторов ошибаются, хотя, например, http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

N.B. Компилятор Solaris диагностирует несовместимые языковые связи в качестве предупреждения:

"t.c", line 11: Warning (Anachronism): Formal argument f of type extern "C" int(*)(int) in call to run(extern "C" int(*)(int), int) is being passed int(*)(int).

Если вы перегрузите run с помощью функции extern "C++", она правильно вызывает extern "C++" one для run(times).