A pergunta era sobre simples c funções, não c ++ static
métodos, conforme esclarecido nos comentários.
Eu entendo o que é uma static
variável, mas o que é uma static
função?
E por que se eu declarar uma função, digamos void print_matrix
, em digamos a.c
(SEM a.h
) e inclua "a.c"
- eu recebo "print_matrix@@....) already defined in a.obj"
, MAS se eu a declarar como static void print_matrix
ela compila?
ATUALIZAÇÃO Apenas para esclarecer as coisas - sei que incluir .c
é ruim, como muitos de vocês apontaram. Eu apenas faço isso para liberar espaço temporariamente main.c
até ter uma idéia melhor de como agrupar todas essas funções em arquivos .h
e .c
arquivos adequados . Apenas uma solução rápida e temporária.
fonte
Há uma grande diferença entre funções estáticas em C e funções membro estáticas em C ++. Em C, uma função estática não é visível fora de sua unidade de conversão, que é o arquivo de objeto em que é compilado. Em outras palavras, tornar uma função estática limita seu escopo. Você pode pensar em uma função estática como "privada" para seu arquivo * .c (embora isso não esteja estritamente correto).
No C ++, "estático" também pode ser aplicado a funções de membros e membros de dados de classes. Um membro de dados estáticos também é chamado de "variável de classe", enquanto um membro de dados não estáticos é uma "variável de instância". Esta é a terminologia Smalltalk. Isso significa que há apenas uma cópia de um membro de dados estáticos compartilhada por todos os objetos de uma classe, enquanto cada objeto tem sua própria cópia de um membro de dados não estáticos. Portanto, um membro de dados estático é essencialmente uma variável global, que é membro de uma classe.
As funções de membro não estático podem acessar todos os membros de dados da classe: estático e não estático. As funções de membro estático podem operar apenas nos membros de dados estáticos.
Uma maneira de pensar sobre isso é que, no C ++, os membros de dados estáticos e as funções de membros estáticos não pertencem a nenhum objeto, mas a toda a classe.
fonte
Existem dois usos para a palavra-chave static quando se trata de funções em C ++.
O primeiro é marcar a função como tendo ligação interna, para que não possa ser referenciada em outras unidades de conversão. Esse uso foi descontinuado em C ++. Os namespaces sem nome são preferidos para esse uso.
O segundo uso está no contexto de uma classe. Se uma classe tem uma função de membro estática, isso significa que a função é um membro da classe (e tem o acesso usual a outros membros), mas não precisa ser invocada por meio de um objeto específico. Em outras palavras, dentro dessa função, não há ponteiro "este".
fonte
Exemplo de escopo mínimo de vários arquivos executáveis
Aqui ilustro como
static
afeta o escopo das definições de função em vários arquivos.ac
main.c
GitHub upstream .
Compile e execute:
Resultado:
Interpretação
sf
, uma para cada arquivof
Como de costume, quanto menor o escopo, melhor, sempre declare funções,
static
se puder.Na programação C, os arquivos são frequentemente usados para representar "classes" e as
static
funções representam métodos "particulares" da classe.Um padrão C comum é passar uma
this
estrutura como o primeiro argumento do "método", que é basicamente o que o C ++ faz sob o capô.O que os padrões dizem sobre isso
C99 N1256 draft 6.7.1 "Especificadores da classe de armazenamento" diz que
static
é um "especificador da classe de armazenamento".6.2.2 / 3 "Ligações de identificadores" diz
static
implicainternal linkage
:e 6.2.2 / 2 diz que
internal linkage
se comporta como no nosso exemplo:onde "unidade de tradução" é um arquivo de origem após o pré-processamento.
Como o GCC o implementa para o ELF (Linux)?
Com a
STB_LOCAL
ligação.Se compilarmos:
e desmonte a tabela de símbolos com:
a saída contém:
portanto, a ligação é a única diferença significativa entre eles.
Value
é apenas o deslocamento para a.bss
seção, portanto esperamos que seja diferente.STB_LOCAL
está documentado na especificação ELF em http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :o que a torna uma escolha perfeita para representar
static
.As funções sem estática são
STB_GLOBAL
e a especificação diz:que é coerente com os erros de link em várias definições não estáticas.
Se acionarmos a otimização
-O3
, osf
símbolo será removido inteiramente da tabela de símbolos: ele não pode ser usado de fora de qualquer maneira. TODO por que manter funções estáticas na tabela de símbolos quando não há otimização? Eles podem ser usados para qualquer coisa?Veja também
extern
é o oposto destatic
, e as funções já estãoextern
por padrão: como uso extern para compartilhar variáveis entre arquivos de origem?Namespace anônimos em C ++
No C ++, convém usar espaços para nome anônimos em vez de estático, o que gera um efeito semelhante, mas oculta ainda mais as definições de tipo: espaços para nome anônimos / anônimos / funções estáticas
fonte
void f() { puts("sf"); }
(ou seja, duas definições def()
) causa comportamento indefinido sem necessidade de diagnóstico. É um problema de qualidade do vinculador ver realmente uma mensagem de erro.A seguir, são apresentadas as funções simples de C - em uma classe C ++, o modificador 'estático' tem outro significado.
Se você tiver apenas um arquivo, esse modificador não fará absolutamente nenhuma diferença. A diferença está em projetos maiores com vários arquivos:
Em C, todo "módulo" (uma combinação de sample.c e sample.h) é compilado independentemente e, posteriormente, todos os arquivos de objetos compilados (sample.o) são vinculados a um arquivo executável pelo vinculador.
Digamos que você tenha vários arquivos incluídos no arquivo principal e dois deles tenham uma função usada apenas internamente por conveniência chamada
add(int a, b)
- o compilador criaria facilmente arquivos de objetos para esses dois módulos, mas o vinculador gerará um erro, porque ele encontra duas funções com o mesmo nome e não sabe qual delas deve usar (mesmo que não haja nada para vincular, porque elas não são usadas em outro lugar, mas em seu próprio arquivo).É por isso que você torna essa função, que é usada apenas interna, uma função estática. Nesse caso, o compilador não cria a bandeira típica "você pode vincular essa coisa" para o vinculador, para que o vinculador não veja essa função e não gere um erro.
fonte
Primeiro: geralmente é uma má idéia incluir um
.cpp
arquivo em outro arquivo - isso gera problemas como este :-) A maneira normal é criar unidades de compilação separadas e adicionar um arquivo de cabeçalho para o arquivo incluído.Em segundo lugar:
C ++ tem alguma terminologia confusa aqui - eu não sabia sobre isso até apontado nos comentários.
a)
static functions
- herdado de C e do que você está falando aqui. Fora de qualquer classe. Uma função estática significa que ela não é visível fora da unidade de compilação atual - portanto, no seu caso, o a.obj possui uma cópia e o outro código possui uma cópia independente. (Inchando o executável final com várias cópias do código).b)
static member function
- o que Orientação a Objetos chama de método estático . Vive dentro de uma classe. Você chama isso com a classe e não através de uma instância de objeto.Essas duas definições diferentes de funções estáticas são completamente diferentes. Tenha cuidado - aqui estejam dragões.
fonte
definições de função estática marcarão esse símbolo como interno. Portanto, não será visível para vinculação externa, mas apenas para funções na mesma unidade de compilação, geralmente o mesmo arquivo.
fonte
Uma função estática é aquela que pode ser chamada na própria classe, em oposição a uma instância da classe.
Por exemplo, um não estático seria:
Este método funciona em uma instância da classe, não na própria classe. No entanto, você pode ter um método estático que pode funcionar sem ter uma instância. Às vezes, isso é usado no padrão Factory:
fonte
Nitidez menor: funções estáticas são visíveis para uma unidade de conversão, que na maioria dos casos práticos é o arquivo no qual a função está definida. O erro que você está recebendo é geralmente chamado de violação da regra de definição única.
O padrão provavelmente diz algo como:
Essa é a maneira C de observar as funções estáticas. No entanto, isso foi preterido em C ++.
Além disso, em C ++, você pode declarar estáticas as funções de membro. Essas são principalmente meta-funções, ou seja, não descrevem / modificam o comportamento / estado de um objeto em particular, mas agem em toda a classe em si. Além disso, isso significa que você não precisa criar um objeto para chamar uma função de membro estático. Além disso, isso também significa que você obtém acesso apenas a variáveis de membro estáticas de dentro dessa função.
Eu adicionaria ao exemplo de Parrot o padrão Singleton, que é baseado nesse tipo de função de membro estático para obter / usar um único objeto durante toda a vida útil de um programa.
fonte
A resposta para a função estática depende do idioma:
1) Em idiomas sem OOPS como C, significa que a função está acessível apenas dentro do arquivo onde está definido.
2) Em linguagens com OOPS como C ++, significa que a função pode ser chamada diretamente na classe sem criar uma instância dela.
fonte
static
tem escopo de arquivo, como em C.Como a função estática é visível apenas neste arquivo. Na verdade, o compilador pode fazer alguma otimização para você se você declarar "estático" para alguma função.
Aqui está um exemplo simples.
main.c
E compile com
Você verá que falhou. Porque você nem implementa a função ghost ().
Mas e se usarmos o seguinte comando.
É um sucesso , e este programa pode ser executado normalmente.
Por quê? Existem 3 pontos-chave.
Somente se essas três condições forem verdadeiras, você poderá passar na compilação. Por causa dessa declaração "estática", o compilador pode confirmar que test () NUNCA será chamado em outro arquivo. Seu compilador pode remover test () ao compilar. Como não precisamos de test (), não importa se ghost () está definido ou implementado.
fonte
Vamos começar no início.
É tudo baseado em uma coisa chamada "ligação":
Se uma função for definida sem um especificador de classe de armazenamento, a função
extern
terá um vínculo por padrão:Isso significa que - se o seu programa contém várias unidades de tradução / arquivos de origem (
.c
ou.cpp
) - a função é visível em todas as unidades de tradução / arquivos de origem que o seu programa possui.Isso pode ser um problema em alguns casos. E se você quiser usar duas funções diferentes (definições), mas com o mesmo nome de função em dois contextos diferentes (na verdade, o contexto do arquivo).
Em C e C ++, o
static
qualificador da classe de armazenamento aplicado a uma função no escopo do arquivo (não uma função membro estática de uma classe em C ++ ou uma função em outro bloco) agora ajuda e significa que a respectiva função só é visível dentro de a unidade de tradução / arquivo de origem em que foi definido e não nos outros TLUs / arquivos.Assim, uma
static
função só faz sentido, se:Seu programa está contido em várias unidades de tradução / arquivos de origem (
.c
ou.cpp
).e
Você deseja limitar o escopo de uma função ao arquivo, no qual a função específica está definida.
Se esses dois requisitos não corresponderem, você não precisa se preocupar em qualificar uma função como
static
.Notas laterais:
Como já mencionado, uma
static
função não tem absolutamente nenhuma diferença entre C e C ++, pois esse é um recurso que C ++ herdou de C.Não importa que, na comunidade C ++, haja um debate comovente sobre a depreciação de funções qualificadas,
static
em comparação com o uso de namespaces não nomeados , primeiro inicializados por um parágrafo fora de lugar no padrão C ++ 03, declarando o uso de funções estáticas obsoletas, que logo foram revisadas pelo próprio comitê e removidas no C ++ 11.Isso estava sujeito a várias perguntas do SO:
Namespaces anônimos / anônimos vs. funções estáticas
Superioridade do namespace sem nome sobre estática?
Por que um espaço para nome sem nome é uma alternativa "superior" à estática?
Descontinuação da palavra-chave estática ... não mais?
De fato, ele ainda não foi preterido pelo padrão C ++. Assim, o uso de
static
funções ainda é legítimo. Mesmo que os namespaces não nomeados possuam vantagens, a discussão sobre o uso ou não de funções estáticas em C ++ está sujeita a uma única opinião (baseada em opiniões) e com a que não é adequada para este site.fonte