Не наружная функция с C-связью

Можно ли объявить функцию с C-связью без наличия внешней привязки? При попытке скомпилировать

extern "C" static void f() {}

Я получаю

f.cc:1: error: invalid use of 'static' in linkage specification

что имеет смысл, в некотором роде. В namespace { extern "C" void f() {} } спецификатор extern, кажется, переопределяет ограниченную область анонимного пространства имен.

Если это невозможно, имеет значение при передаче указателя функции на C?

Ответ 1

Вы можете сделать

extern "C" {
  static void f() {}
}

Это даст функцию f типа C, которая на практике означает, что она использует соглашение о вызове C на вашей платформе. Имя функции все равно будет иметь С++/внутреннюю связь, поскольку спецификация языкового связывания применима только к именам функций внешней связи.

Если вы укажете extern "C" непосредственно в объявлении, стандарт указывает, что значение extern "C" считается также спецификатором класса хранения, поэтому, если вы добавите static, вы получите конфликт.

Имеет ли значение при передаче указателя функции на C

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

Ответ 2

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

Основная причина, по которой передается указатель на нестационарную функцию-член, не работает так легко, потому что вам также нужно будет передавать информацию об указателе объекта this, что обычно происходит как неявное, невидимый параметр для любой функции-члена.

Ответ 3

Я просто успешно использовал ответы Йоханнеса. Спасибо, чувак!

Так как я не могу (пока) комментировать, но могу ответить, позвольте мне просто добавить эту точку данных.

Я напечатал в <the-file>.cpp (подробности милосердно опущены:-):

extern "C" {
    extern int myfunction(<the-args>);
}

extern int myfunction(<the-args>) {
    <the-code>
}

а также:

extern "C" {
    static int myfunction(<the-args>);
}

static int my function(<the-args>) {
    <the-code>
}

Я скомпилировал оба пути и сделал:

nm -g <the-file>.o | grep myfuncion

в двух объектных файлах по очереди.

Я заметил, что для extern это была запись, но для статического случая ее не было.

Итак, я достаточно доволен, что внешний "extern" просто устанавливает связь, а режим адресации статический для статического случая.