2017-02-11 30 views
0

Я был смущен тем, следует ли использовать extern для форвардных объявлений функций в C. Каждый сценарий - это отдельный файл .c/.cpp. Я понял из этого вопроса - External linkage of const in C, что если все файлы .c, я не должен использовать extern для прямого объявления независимо от того, определена ли функция в том же файле или нет.forward statement using extern (в контексте C/C++)

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

+0

Функции 'extern' по умолчанию, вы можете использовать или опустить это ключевое слово из прямого объявления, как хотите, значение не изменяется. –

+0

@ н.м. используя extern, компилятор игнорирует подпись, я имею в виду, что проверка типов не выполняется. Поэтому он не должен использоваться, когда это не требуется. – Bhargav

+1

"компилятор игнорирует подпись" Неправильно. Кто вам сказал? –

ответ

2

В языке C есть такая вещь, как extern inline, которая имеет особое значение и в которой явно выражена extern.

Помимо этого, в объявлениях functon никогда не возникает смысла указывать явное выражение extern, так как функции в C и C++ всегда имеют внешнюю связь defualt.

Вопрос о «разных языках», вероятно, относится к таким вещам, как extern "C", но это совершенно другой контур из простого extern.

+0

Спасибо, это меня смутило. Я смешал выражение функции extern с использованием extern «C» и хотел знать, когда внешние аргументы вызывают объявления функций. – Bhargav

+0

Имеет ли объявление функции в области блока различие: i.e 'void f() {extern void g(); } '? – 0x499602D2

0

Функции имеют внешнее связывание по умолчанию, что означает, что

extern int foo(void); 

и

int foo(void); 

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

В частности, наличие или отсутствие extern имеет никакого эффекта на проверку типа и не зависит ли эта функция от другого языка.

1

Я думаю, когда функция, объявленная вперед, определяется на другом языке, чем вызов, требуется внешний интерфейс.

Я должен предупредить вас, что ваш вопрос плохо сформулирован. Я уверен, что вы заинтересованы в том, когда использовать

extern "C" int foo(int); 

в C++, но я не уверен, и у меня есть надежда, что я не тратить свое время.

Давайте различать компилятор и компоновщик. Я оставляю некоторые детали, но ничего не влияет на ответ на ваш вопрос.

A Прочая декларация используется компилятором. При объявлении функции вы даете компилятору информацию о том, как он используется. Вы объявляете функцию F, а когда используется компилятор, F используется, он знает, что делать. (В K & R дней, в отсутствие объявления, компилятор использовал значения по умолчанию, иногда приводящие к веселым результатам. Поэтому теперь они являются обязательными как для C, так и для C++.)

Обычно переднее объявление функции представляет собой функциональный прототип : он предоставляет типы параметров. В C это не является строго необходимым. Вы можете написать

int foo(); 

который сообщает компилятор foo является функцией, возвращающей int, но не какие параметры он принимает. Затем вы становитесь ответственным за то, чтобы получить право, потому что компилятор не может проверить.

Объявление extern - будь то функция или переменная - уведомляет компилятор о символе и его типе и говорит, что определение будет предоставлено другим модулем. Компилятор оставляет заполнитель для компоновщика для заполнения позже.

Если вы посмотрите на Getopt (3) человек страницы, к примеру, вы увидите optarg объявлен extern; он определен в библиотеке времени выполнения C, но вы можете использовать его, потому что он был объявлен.

Теперь мы подошли к компоновщику и extern "C" C++.

К компоновщику модуль предоставляет символы. Глобальные переменные и функции, не объявленные static, имеют внешнюю связь, что означает, что они могут использоваться другими модулями.

В C есть соответствие 1: 1 между именами функций и внешними символами. Это символ. Например, Getopt (3) имеет символ с тем же именем в стандартной библиотеке C, LIBC:

$ nm -g $(find /usr/lib/ -name libc.a) 2>/dev/null | grep 'T getopt' 
0000000000001620 T getopt 
0000000000000000 T getopt_long 
0000000000000040 T getopt_long_only 

В C++ имя не символ. Функция C++ может быть перегружена; одно и то же имя может представлять разные функции с различными параметрами. Компилятор создает символ, который кодирует типы параметров. Сравните:

$ echo 'int foo(int foo) { return foo * foo; }' > a.c && cc -c a.c && nm a.o 
0000000000000000 T foo 
$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o 
0000000000000000 T _Z3fooi 

Кодирование имени символа часто называют имя коверкая. нм (1) имеет функцию декодирования:

$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm -C a.o 
0000000000000000 T foo(int) 

Обратите внимание, что тип параметра отображается рядом с именем.

В C++ extern "C" объявляет или определяет функцию как функцию C. Вот определение:

$ echo 'extern "C" int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o 
0000000000000000 T foo 
  • В заявлении он сообщает компилятору, что функция определена в другом месте, и использования символ C.

  • В определении указано компилятору emit символ C, т. Е. Не изменяет имя, чтобы эта функция могла использоваться другими модулями C.

Я надеюсь, что ответит на ваш вопрос.