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

Возможная двусмысленность с внешними "C", перегрузками и указателями функций

С нормальными функциями можно написать

extern "C" int Frotz(int);  // in a header

int Frotz(int x) { return x; }

С указателями функций, однако, это, похоже, было непоследовательно реализовано между компиляторами.

extern "C" int Klutz(int (*)(int), int);

int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }

В объявлении аргумент также extern "C". В определении большинство компиляторов, похоже, соответствуют этим функциям и выполняют функцию Klutz a extern "C". Однако составители Sun и Cray интерпретируют эти функции как разные, создавая перегруженный int Klutz(int (*fptr)(int), int x), который позже генерирует ошибку времени привязки.

Несмотря на то, что раздел 7.5.5 на С++ 98 и С++ 11 гарантирует интерпретацию Frotz, я не могу сказать, является ли стандарт двусмысленным в отношении того, должно ли соответствие extern "C" происходить до или после проверки перегрузки.

Если Klutz выше генерирует искаженный (С++) символ или символ extern "C"?

EDIT 1

Я мог бы использовать typedef, чтобы устранить смещение указателя функции на C или С++ ABI, но меня интересует, содержит ли здесь код (a) Klutz для связи С++, (b) определяет его, чтобы иметь C link или (c) является неоднозначным в соответствии со стандартом, поэтому компиляторы могут свободно выбирать, как интерпретировать его.

EDIT 2

Это, по-видимому, известная проблема, по крайней мере, теми компиляторами, в которых есть поисковые трекеры. В моих тестах GCC, Clang, Intel, MSVC, IBM XL, PathScale, PGI и Open64 не различают типы функций, которые идентичны, кроме языковой привязки, как это явно требуется стандартом (см. Раздел 7.5.1, приведенный в принятый ответ). Исправление этого может сломать много существующего кода и потребовать изменения ABI. Я не знаю какого-либо компилятора, который на самом деле использует другое соглашение о вызове для связи языка C и С++.

  • Ошибка GCC: "Поиск причин, чтобы попросить удалить эту функцию из следующего стандарта, относится к релевантным;-)"... "И мы даже можем принять решение о официальном WONTFIX".

  • Ошибка Clang: "Я напугана тем, что на самом деле применяю это правило, потому что это правильно означает создание языковой связки части канонический тип, который сломает тонну кода".

4b9b3361

Ответ 1

C ABI и С++ ABI не гарантируются одинаковыми. Таким образом, указатель функции extern "C" - это другой тип из указателя функции С++. Вам нужно что-то вроде этого:

extern "C" {
    typedef int (*KlutzFuncType)(int);
    int Klutz (KlutzFuncType, int);
}

int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); }

Здесь обсуждается этот вопрос .


У меня есть только копия черновик. Из 7.5p1:

Два типа функций с различными языковыми связями - это разные типы, даже если они идентичны.

Мое прочтение этого состоит в том, что первый параметр вашего первого Klutz имеет другой тип, чем первый параметр вашего второго Klutz, поэтому ваш второй Klutz должен иметь ссылку на С++.


Существуют реализации С++, которые не учитывают языковые связи для типов функций, несмотря на то, что говорит стандарт. В следующем фрагменте кода KlutzCxxFuncType относится к функции с С++-связью, а KlutzCFuncType относится к функции с C-связью.

typedef int (*KlutzCxxFuncType)(int);

extern "C" {
    typedef int (*KlutzCFuncType)(int);
    int Klutz (KlutzCFuncType, int);
}

int Klutz (KlutzCxxFuncType fptr, int x) { return (*fptr)(x); }
int Klutz (KlutzCFuncType fptr, int x) { return (*fptr)(x); }

Компилятор, который не различает типы функций, основанные на языковой привязке, генерирует ошибку переопределения этого кода. Например, g++ 4.7.2 будет выдавать:

prog.cpp: In function ‘int Klutz(KlutzCFuncType, int)’:
prog.cpp:9:5: error: redefinition of ‘int Klutz(KlutzCFuncType, int)’
prog.cpp:8:5: error: ‘int Klutz(KlutzCxxFuncType, int)’ previously defined here