Qual é o sentido de tornar uma função estática em C?
Qual é o sentido de tornar uma função estática em C?
Respostas:
Criar uma função a static
oculta de outras unidades de tradução, o que ajuda a fornecer o encapsulamento .
helper_file.c
int f1(int); /* prototype */
static int f2(int); /* prototype */
int f1(int foo) {
return f2(foo); /* ok, f2 is in the same translation unit */
/* (basically same .c file) as f1 */
}
int f2(int foo) {
return 42 + foo;
}
main.c :
int f1(int); /* prototype */
int f2(int); /* prototype */
int main(void) {
f1(10); /* ok, f1 is visible to the linker */
f2(12); /* nope, f2 is not visible to the linker */
return 0;
}
#include <helper_file.c>
? Eu acho que isso tornaria uma única unidade de tradução então ...
gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c
. Os protótipos para as funções estão presentes nos dois arquivos de origem (não há necessidade de arquivos de cabeçalho). O vinculador resolverá as funções.
pmg é direto sobre encapsulamento; além de ocultar a função de outras unidades de conversão (ou melhor, por causa disso), as funções de criação static
também podem conferir benefícios de desempenho na presença de otimizações do compilador.
Como uma static
função não pode ser chamada de qualquer lugar fora da unidade de tradução atual (a menos que o código leve um ponteiro para seu endereço), o compilador controla todos os pontos de chamada nela.
Isso significa que é livre usar uma ABI fora do padrão, incorporá-la inteiramente ou executar qualquer número de outras otimizações que talvez não sejam possíveis para uma função com ligação externa.
static
função escapar da unidade de tradução atual, essa função poderá ser chamada diretamente de outras unidades de tradução.
A static
palavra-chave em C é usada em um arquivo compilado (.c em oposição a .h) para que a função exista apenas nesse arquivo.
Normalmente, quando você cria uma função, o compilador gera um cruft que o vinculador pode usar para, bem, vincular uma chamada de função a essa função. Se você usar a palavra-chave estática, outras funções no mesmo arquivo poderão chamar essa função (porque isso pode ser feito sem o recurso ao vinculador), enquanto o vinculador não possui informações que permitam que outros arquivos acessem a função.
Olhando para as postagens acima, gostaria de apontar um detalhe.
Suponha que nosso arquivo principal ("main.c") seja assim:
#include "header.h"
int main(void) {
FunctionInHeader();
}
Agora considere três casos:
Caso 1: Nosso arquivo de cabeçalho ("header.h") fica assim:
#include <stdio.h>
static void FunctionInHeader();
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Em seguida, o seguinte comando no linux:
gcc main.c header.h -o main
terá sucesso ! Depois disso, se alguém executar
./main
A saída será
Chamando a função dentro do cabeçalho
Qual é o que essa função estática deve imprimir.
Caso 2: Nosso arquivo de cabeçalho ("header.h") se parece com o seguinte:
static void FunctionInHeader();
e também temos mais um arquivo "header.c", que se parece com isso:
#include <stdio.h>
#include "header.h"
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Em seguida, o seguinte comando
gcc main.c header.h header.c -o main
dará um erro.
Caso 3:
Semelhante ao caso 2, exceto que agora nosso arquivo de cabeçalho ("header.h") é:
void FunctionInHeader(); // keyword static removed
Então, o mesmo comando do caso 2 será bem-sucedido e a execução de ./main continuará fornecendo o resultado esperado.
Portanto, a partir desses testes (executados na máquina Acer x86, Ubuntu OS), assumi que
A palavra-chave estática impede que a função seja chamada em outro arquivo * .c que não seja onde está definido.
Corrija-me se eu estiver errada.
Programadores C usam o atributo static para ocultar declarações de variáveis e funções dentro de módulos, da mesma forma que você usaria declarações públicas e privadas em Java e C ++. Os arquivos de origem C desempenham o papel de módulos. Qualquer variável global ou função declarada com o atributo estático é privada para esse módulo. Da mesma forma, qualquer variável global ou função declarada sem o atributo estático é pública e pode ser acessada por qualquer outro módulo. É uma boa prática de programação proteger suas variáveis e funções com o atributo estático sempre que possível.
A resposta da pmg é muito convincente. Se você deseja saber como as declarações estáticas funcionam no nível do objeto, as informações abaixo podem ser interessantes para você. Reutilizei o mesmo programa escrito por pmg e o compilei em um arquivo .so (objeto compartilhado)
O conteúdo a seguir é depois de despejar o arquivo .so em algo legível por humanos
0000000000000675 f1 : endereço da função f1
000000000000068c f2 : endereço da função f2 (staticc)
observe a diferença no endereço da função, isso significa alguma coisa. Para uma função declarada com endereço diferente, pode muito bem significar que f2 mora muito longe ou em um segmento diferente do arquivo de objeto.
Os vinculadores usam algo chamado PLT (tabela de vinculação de procedimentos) e GOT (tabela de compensações globais) para entender os símbolos aos quais eles têm acesso.
Por enquanto, pense que GOT e PLT vinculam magicamente todos os endereços e uma seção dinâmica contém informações de todas essas funções que são visíveis pelo vinculador.
Depois de despejar a seção dinâmica do arquivo .so, obtemos várias entradas, mas apenas interessadas na função f1 e f2 .
A seção dinâmica mantém a entrada apenas para a função f1 no endereço 0000000000000675 e não para f2 !
Num: Valor Tamanho Tipo Vinculação Vis Ndx Name
9: 0000000000000675 23 FUNC GLOBAL DEFAULT 11 f1
E é isso !. A partir disso, fica claro que o vinculador não conseguiu encontrar a função f2 , pois não está na seção dinâmica do arquivo .so.
Quando for necessário restringir o acesso a algumas funções, usaremos a palavra-chave estática ao definir e declarar uma função.
/* file ab.c */
static void function1(void)
{
puts("function1 called");
}
And store the following code in another file ab1.c
/* file ab1.c */
int main(void)
{
function1();
getchar();
return 0;
}
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */