как extern C разрешает код C++ в файле C?

Чтобы использовать код C++ в файле C, я прочитал, что мы можем просто сделать extern "C" { (where the c++ code goes here)}, но когда я пытаюсь что-то напечатать с помощью cout, я продолжаю получать сообщение об ошибке, потому что он не распознает библиотеку. Я думаю, что просто запутался в том, как extern "C" позволяет вам использовать код C++ в C.


person Sandra Delatorre    schedule 22.04.2016    source источник


Ответы (4)


Верно и обратное. Вы можете использовать extern C для добавления кода, который вы хотите скомпилировать как код C с помощью компилятора C++.

Если я что-то упустил, вы не можете скомпилировать код C++ с помощью компилятора C.

person It'sPete    schedule 22.04.2016

Конструкция extern "C" представляет собой синтаксис, специфичный для C++, и ни один компилятор C не поймет его.

Вот почему вы почти всегда будете видеть его в паре с некоторой условной компиляцией, например

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif

Что extern "C" делает, так это просто запрещает искажать имена означает, что символы, определенные в исходном файле C++, могут использоваться в программе C.

Это позволяет вам иметь проект со смешанными исходными кодами C и C++, а исходный код C может вызывать функции C++, которые были определены как extern "C".

Очень простой и глупый пример, просто чтобы показать суть:

Допустим, у нас есть исходный файл C, скомпилированный компилятором C:

#include <stdio.h>

void foo(void);  // Declare function prototype, so it can be called

int main(void)
{
    printf("Calling foo...\n");
    foo();
    printf("Done\n");

    return 0;
}

Затем у нас есть исходный файл C++ для функции foo:

#include <iostream>

extern "C" void foo()
{
    std::cout << "Hello from foo\n";
}

Исходный файл C компилируется компилятором C, а исходный файл C++ компилируется компилятором C++. Затем два объектных файла связываются вместе, чтобы сформировать исполняемую программу. Поскольку foo было определено как extern "C", его имя символа в объектном файле не искажено, и компоновщик может разрешить ссылку из объектного файла, созданного компилятором C.

Это работает и в другом направлении. Поскольку символы в C не искажаются, компилятор C++ должен знать об этом, и это делается путем объявления символов C extern "C", обычно в заголовочном файле с использованием условной компиляции, как показано выше. Если бы extern "C" не использовался, компилятор C++ подумал бы, что символы были символами C++, и исказил бы имена, что привело бы к проблемам компоновщика, когда компоновщик не может найти искаженные символы.

Столь же глупый пример: сначала исходный файл C++

#include <iostream>

extern "C" void bar();  // Declare function prototype as an unmangled symbol

int main()
{
    std::cout << "Calling bar...\n";
    bar();
}

Затем исходный файл C

#include <stdio.h>

void bar(void)
{
    printf("Inside bar\n");
}
person Some programmer dude    schedule 22.04.2016
comment
extern "C" это нечто большее, чем запрет на искажение имен. Он также делает другие вещи, чтобы обеспечить взаимодействие между C и C++. - person Peter; 22.04.2016
comment
@Питер. Что еще (помимо перегрузки)? - person Mad Physicist; 08.07.2020
comment
@MadPhysicist - ряд вещей. Одним из примеров является то, что функции extern "C" могут использовать другое соглашение о вызовах, чем функции, не указанные как extern "C", что влияет на то, как на самом деле передаются аргументы (например, если они помещаются в стек, они могут помещаться в другой порядок - и, следовательно, их необходимо извлекать). в другом порядке для использования в функции). Еще одно отличие состоит в том, что все, что объявлено как extern "C", имеет внешнюю связь. Есть еще несколько отличий. - person Peter; 08.07.2020
comment
@Питер. Спасибо за объяснение. Означает ли это, что я не могу иметь внешний C и в то же время осмысленно встроенный? - person Mad Physicist; 08.07.2020
comment
@MadPhysicist - это зависит от того, что вы подразумеваете под осмысленно встроенным. Одной из целей extern "C" является возможность вызова кода C++ из C через интерфейс (и наоборот), и эта граница повлияет на то, будет ли какой-либо из компиляторов встроен — даже если компиляторы C и C++ принадлежат одному и тому же поставщику, тем более, если из разные продавцы. - person Peter; 09.07.2020
comment
@Питер. Я имею в виду, что если я #include файл C в свой файл C++ со встроенными функциями, будут ли они правильно встроены с extern C в файле C, или я должен опустить его и надеяться, что синтаксис сработает? - person Mad Physicist; 09.07.2020
comment
@MadPhysicist - это зависит от реализации (инструментальной цепочки и т. д.). Даже когда функция явно помечена inline, это всего лишь подсказка по стандарту, поэтому она может вообще не быть встроенной. И наоборот, большинство современных реализаций с радостью встраивают некоторые функции, даже если их об этом не просят, потому что они могут сделать лучший выбор, чем большинство программистов. Если реализация имеет видимость определения (а не только объявления) функции extern "C", решение будет принято реализацией. - person Peter; 09.07.2020
comment
@Питер. Спасибо за помощь. Приятно знать, что я могу полагаться на нормальное поведение встраивания даже в блоке extern "C". - person Mad Physicist; 09.07.2020

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

int add(int a, int b) {
    return a+b;
}

На самом деле в библиотеке будет какое-то причудливое имя для обозначения параметров, поэтому, если вы определите другую функцию, например:

double add(double a, double b) {
    return a+b;
}

Что он знает, кому звонить. Вам это не нужно, если вы пытаетесь использовать библиотеку C, и для этого предназначен extern "C". Все это говорит о том, что extern "C" не позволяет C++ в программе C.

person CrazyCasta    schedule 22.04.2016

Экспортированные символы C++, сгенерированные моим компилятором, искажаются, чтобы включить в компоновщик дополнительную информацию о типе символа.

Таким образом, следующие перегруженные функции будут различимы компоновщиком в C++, но не в C:

  • int fn();
  • int fn(int);
  • int fn(char*);
  • int fn(char*) const;
  • int fn(const char*);

Синтаксис extern "C" { ... } позволяет определять символы (или ссылки на символы C) в коде C++ без использования правил mangling. Это позволяет связывать такой код C++ с библиотеками C.

person geipel    schedule 22.04.2016