Como é que um extern "C" declaração de trabalho?
Pergunta
Eu estou tomando linguagens de programação curso e estamos a falar sobre a extern "C"
declaração.
Como é que esta declaração de trabalho em um nível mais profundo, diferente de "ele interfaces de C e C++"?Como isso afeta as ligações que ocorrem no programa bem?
Solução
extern "C"
é usado para garantir que os símbolos a seguir não sejam mutilado (decorado).
Exemplo:
Digamos que temos o seguinte código em um arquivo chamado test.cpp
:
extern "C" {
int foo() {
return 1;
}
}
int bar() {
return 1;
}
Se você correr gcc -c test.cpp -o test.o
Dê uma olhada nos nomes dos símbolos:
00000010 T _Z3BARV
00000000 T FOO
foo()
Mantém o nome.
Outras dicas
Vejamos uma função típica que pode compilar em C e C ++:
int Add (int a, int b)
{
return a+b;
}
Agora, em C, a função é chamada de "_add" internamente. Enquanto a função C ++ é chamada de algo completamente diferente usando um sistema chamado nomes de nomes. É basicamente uma maneira de nomear uma função para que a mesma função com parâmetros diferentes tenha um nome interno diferente.
Portanto, se Add () for definido em add.c e você ter o protótipo em add.h, você terá um problema se tentar incluir add.h em um arquivo C ++. Como o código C ++ está procurando uma função com um nome diferente do que add.c, você receberá um erro de vinculador. Para contornar esse problema, você deve incluir add.c por este método:
extern "C"
{
#include "add.h"
}
Agora, o código C ++ será vinculado ao _Add em vez da versão mutilada do nome C ++.
Esse é um dos usos da expressão. Resumindo, se você precisar compilar o código que é estritamente C em um programa C ++ (por meio de uma instrução INCLUÍDO ou ALGUNS MUNDOS), você precisa embrulhá -lo com uma declaração externa "C" {...}.
Quando você sinaliza um bloco de código com "C" externo, você está dizendo ao sistema para usar a ligação do estilo C.
Isso, principalmente, afeta a maneira como o vinculador engana os nomes. Em vez de usar o nome do estilo C ++ (que é mais complexo para suportar sobrecargas do operador), você obtém a nomeação padrão do estilo C do vinculador.
Em C ++, o nome/símbolo das funções é realmente renomeado para outra coisa, de modo que diferentes classes/namespaces podem ter funções das mesmas assinaturas. Em C, as funções são todas definidas globalmente e esse processo de renomeação personalizado é necessário.
Para fazer C ++ e C conversarem entre si, "extern c" instrui o compilador a não usar a Convenção C.
Deve -se notar que extern "C"
também modifica os tipos de funções. Ele não apenas modifica as coisas em níveis mais baixos:
extern "C" typedef void (*function_ptr_t)();
void foo();
int main() { function_ptr_t fptr = &foo; } // error!
O tipo de &foo
Não é igual ao tipo que o typedef designa (embora o código seja aceito por alguns, mas não todos os compiladores).
extern c afeta o nome do nome do compilador C ++. É uma maneira de fazer com que o compilador C ++ não gerencie nomes, ou melhor, para gerenciá -los da mesma maneira que um compilador C faria. É assim que ele interfina C e C ++.
Como um exemplo:
extern "C" void foo(int i);
permitirá que a função seja implementada em um módulo C, mas permitirá que ela seja chamada de um módulo C ++.
O problema surge ao tentar obter um módulo C para chamar uma função C ++ (obviamente C não pode usar classes C ++) definidas em um módulo C ++. O compilador C não gosta extern "C"
.
Então você precisa usar isso:
#ifdef __cplusplus
extern "C" {
#endif
void foo(int i);
#ifdef __cplusplus
}
#endif
Agora, quando isso aparecer em um arquivo de cabeçalho, os compiladores C e C ++ ficarão felizes com a declaração e agora poderão ser definidos no módulo C ou C ++ e podem ser chamados pelo código C e C ++.
Externo "C" indica que o código fechado usa vinculação e nome do estilo C. O C ++ usa um formato de mangueira de nome mais complexo. Aqui está um exemplo:
http://en.wikipedia.org/wiki/Name_Mangling
int example(int alpha, char beta);
Em C: _example
em C ++: __Z7exampleic
ATUALIZAÇÃO: Como observa Gmannickg nos comentários, o padrão de manglom de nome é dependente do compilador.
extern "c", é uma palavra -chave para declarar uma função com as ligações C, porque o compilador C e o compilador C ++ traduzirão a fonte em formato diferente no arquivo de objeto:
Por exemplo, um snippet de código é o seguinte:
int _cdecl func1(void) {return 0}
int _stdcall func2(int) {return 0}
int _fastcall func3(void) {return 1}
Os compiladores C de 32 bits traduzirão o código no formulário da seguinte forma:
_func1
_func2@4
@func3@4
No CDECL, Func1 se traduzirá como '_nome'
No stdcall, o func2 se traduzirá como '_name@x'
No FastCall, o Func2 se traduzirá como '@nome@x'
'X'significa quantos bytes dos parâmetros na lista de parâmetros.
Convenção de 64 bits no Windows não tem sublinhado líder
Em C ++, classes, modelos, espaços para nome e sobrecarga do operador são introduzidos, pois não é permitido duas funções com o mesmo nome, o compilador C ++ fornece as informações de tipo no nome do símbolo,
Por exemplo, um snippet de código é o seguinte:
int func(void) {return 1;}
int func(int) {return 0;}
int func_call(void) {int m=func(), n=func(0);}
O compilador C ++ traduzirá o código da seguinte forma:
int func_v(void) {return 1;}
int func_i(int) {return 0;}
int func_call(void) {int m=_func_v(), n=_func_i(0);}
'_v' e '_i' são informações de tipo de 'void' e 'int'
Aqui está uma citação do msdn
"A palavra-chave externo declara uma variável ou função e especifica que ele tem ligação externa a (o seu nome é visível a partir de arquivos diferente daquele no qual ela está definida).Ao modificar uma variável, externo especifica que a variável tem a duração de estática (é alocado quando o programa começa e desalocado quando o programa termina).A variável ou função pode ser definida em outro arquivo de origem, ou mais tarde no mesmo arquivo.Declarações de variáveis e funções no âmbito do ficheiro são externas por padrão."
http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx