Ele é usado em C e C ++.
Como você adivinhou, a static
parte limita seu escopo a essa unidade de compilação . Ele também fornece inicialização estática. const
apenas diz ao compilador para não permitir que ninguém o modifique. Essa variável é colocada no segmento de dados ou bss dependendo da arquitetura e pode estar na memória marcada como somente leitura.
Tudo isso é como C trata essas variáveis (ou como C ++ trata variáveis de namespace). Em C ++, um membro marcado static
é compartilhado por todas as instâncias de uma determinada classe. Se é privado ou não, não afeta o fato de que uma variável é compartilhada por várias instâncias. Tendo const
lá irá avisá-lo se algum código seria tentar modificar isso.
Se fosse estritamente privado, cada instância da classe obteria sua própria versão (não obstante o otimizador).
Muitas pessoas deram a resposta básica, mas ninguém apontou que em C ++ os
const
padrões sãostatic
nonamespace
nível (e alguns deram informações erradas). Consulte a seção 3.5.3 do padrão C ++ 98.Primeiro, algumas informações básicas:
Unidade de tradução: um arquivo de origem após o pré-processador (recursivamente) incluir todos os seus arquivos de inclusão.
Ligação estática: um símbolo está disponível apenas em sua unidade de tradução.
Ligação externa: Um símbolo está disponível em outras unidades de tradução.
No
namespace
nívelIsso inclui o namespace global também conhecido como variáveis globais .
No nível de função
static
significa que o valor é mantido entre as chamadas de função.A semântica das
static
variáveis de função é semelhante às variáveis globais no sentido de que residem no segmento de dados do programa (e não na pilha ou no heap). Consulte esta questão para obter mais detalhes sobrestatic
o tempo de vida das variáveis.No
class
nívelstatic
significa que o valor é compartilhado entre todas as instâncias da classe econst
significa que ele não muda.fonte
const int *foo(int x) {const int b=x;return &b};
relação aconst int *foo(int x) {static const int b=x;return &b};
const
apenas implicarstatic
no último.const
declaração implicastatic
isso também? Tipo, se você jogarconst
fora e modificar o valor, todos os valores serão modificados?const
não implica estático no nível da função, isso seria um pesadelo de simultaneidade (const! = Expressão constante), tudo no nível da função é implicitamenteauto
. Uma vez que essa questão também está marcada como [c], devo mencionar que um nível globalconst int
está implicitamenteextern
em C. No entanto, as regras que você tem aqui descrevem perfeitamente C ++.static
indica que a variável tem duração estática (existe apenas uma cópia, que dura do início do programa até o seu fim), e tem ligação interna / estática se não for especificado de outra forma (isso é substituído pela função linkage para variáveis estáticas locais ou linkage da classe para membros estáticos). As principais diferenças estão no que isso implica em cada situação em questatic
é válido.Essa linha de código pode realmente aparecer em vários contextos diferentes e, embora se comporte aproximadamente da mesma forma, existem pequenas diferenças.
Escopo do namespace
'
i
' estará visível em todas as unidades de tradução que incluem o cabeçalho. No entanto, a menos que você realmente use o endereço do objeto (por exemplo. '&i
'), Tenho certeza de que o compilador tratará 'i
' simplesmente como um tipo seguro0
. Quando mais duas unidades de tradução assumirem o '&i
', o endereço será diferente para cada unidade de tradução.'
i
' tem ligação interna e, portanto, não pode ser referido de fora desta unidade de tradução. No entanto, novamente, a menos que você use seu endereço, ele provavelmente será tratado como um tipo seguro0
.Algo que vale a pena ressaltar é que a seguinte declaração:
é exatamente o mesmo que
static const int i = 0
. Uma variável em um namespace declarada comconst
e não explicitamente declarada comextern
é implicitamente estática. Se você pensar sobre isso, era intenção do comitê C ++ permitir queconst
variáveis fossem declaradas em arquivos de cabeçalho sem sempre precisar dastatic
palavra-chave para evitar quebrar o ODR.Escopo da classe
No exemplo acima, o padrão especifica explicitamente que '
i
' não precisa ser definido se seu endereço não for obrigatório. Em outras palavras, se você usar apenas 'i
' como um 0 de tipo seguro, o compilador não o definirá. Uma diferença entre as versões de classe e espaço de nomes é que o endereço de 'i
' (se usado em duas ou mais unidades de tradução) será o mesmo para o membro da classe. Onde o endereço é usado, você deve ter uma definição para ele:fonte
É uma pequena otimização de espaço.
Quando voce diz
Você não está definindo uma constante, mas criando uma variável somente leitura. O compilador é inteligente o suficiente para usar 42 sempre que encontrar foo, mas também alocará espaço na área de dados inicializada para ele. Isso é feito porque, conforme definido, foo tem ligação externa. Outra unidade de compilação pode dizer:
extern const int foo;
Para obter acesso ao seu valor. Essa não é uma boa prática, já que essa unidade de compilação não tem ideia do valor de foo. Ele apenas sabe que é um const int e precisa recarregar o valor da memória sempre que for usado.
Agora, declarando que é estático:
O compilador pode fazer sua otimização usual, mas também pode dizer "ei, ninguém fora desta unidade de compilação pode ver foo e sei que é sempre 42, então não há necessidade de alocar espaço para ele."
Devo também observar que em C ++, a maneira preferida de evitar que os nomes escapem da unidade de compilação atual é usar um namespace anônimo:
fonte
Está faltando um 'int'. Deveria ser:
Em C e C ++, ele declara uma constante inteira com escopo de arquivo local de valor 42.
Por que 42? Se você ainda não sabe (e é difícil acreditar que não sabe), é uma referência à Resposta à Vida, ao Universo e a tudo .
fonte
Em C ++,
é a forma preferida de definir e usar constantes. Ou seja, use isso ao invés de
porque não subverte o sistema de segurança de tipo.
fonte
A todas as ótimas respostas, quero adicionar um pequeno detalhe:
Se você escrever plug-ins (por exemplo, DLLs ou bibliotecas .so para serem carregadas por um sistema CAD), a estática é um salva-vidas que evita colisões de nomes como esta:
Pior ainda: a etapa 3 pode se comportar de maneira diferente dependendo da otimização do compilador, mecanismo de carregamento do plugin, etc.
Tive esse problema uma vez com duas funções auxiliares (mesmo nome, comportamento diferente) em dois plug-ins. Declará-los estáticos resolveu o problema.
fonte
De acordo com a especificação C99 / GNU99:
static
é especificador de classe de armazenamento
objetos de escopo de nível de arquivo por padrão têm ligação externa
const
é qualificador de tipo (é uma parte do tipo)
palavra-chave aplicada à instância esquerda imediata - ou seja
MyObj const * myVar;
- ponteiro não qualificado para o tipo de objeto qualificado constMyObj * const myVar;
- ponteiro qualificado const para tipo de objeto não qualificadoUso mais à esquerda - aplicado ao tipo de objeto, não variável
const MyObj * myVar;
- ponteiro não qualificado para o tipo de objeto qualificado constPORTANTO:
static NSString * const myVar;
- ponteiro constante para string imutável com ligação interna.A ausência da
static
palavra - chave tornará o nome da variável global e pode levar a conflitos de nome no aplicativo.fonte
inline
Variáveis C ++ 17Se você pesquisou "C ++ const static" no Google, é muito provável que o que você realmente queira usar sejam as variáveis inline do C ++ 17 .
Este incrível recurso do C ++ 17 nos permite:
constexpr
: Como declarar constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Compile e execute:
GitHub upstream .
Consulte também: Como funcionam as variáveis embutidas?
Padrão C ++ em variáveis embutidas
O padrão C ++ garante que os endereços serão os mesmos. Rascunho do padrão C ++ 17 N4659 10.1.6 "O especificador embutido":
cppreference https://en.cppreference.com/w/cpp/language/inline explica que se
static
não for fornecido, então tem uma ligação externa.Implementação de variável inline GCC
Podemos observar como isso é implementado com:
que contém:
e
man nm
fala sobreu
:portanto, vemos que há uma extensão ELF dedicada para isso.
Pré-C ++ 17:
extern const
Antes do C ++ 17, e no C, podemos obter um efeito muito semelhante com um
extern const
, que levará ao uso de um único local de memória.As desvantagens
inline
são:constexpr
com esta técnica, apenasinline
permite que: Como declarar constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub upstream .
Alternativas apenas de cabeçalho pré-C ++ 17
Eles não são tão bons quanto a
extern
solução, mas funcionam e ocupam apenas um único local de memória:Uma
constexpr
função, porqueconstexpr
implicainline
einline
permite (força) que a definição apareça em cada unidade de tradução :e aposto que qualquer compilador decente fará a chamada inline.
Você também pode usar uma variável
const
ouconstexpr
estática como em:mas você não pode fazer coisas como pegar seu endereço, ou então ele se torna usado por odr, veja também: Definindo membros de dados estáticos constexpr
C
Em C, a situação é a mesma que em C ++ pré C ++ 17, enviei um exemplo em: O que significa "estático" em C?
A única diferença é que em C ++,
const
implicastatic
para globais, mas não em C: C ++ semântica de `const estático` vs` const`Há alguma maneira de embuti-lo totalmente?
TODO: existe alguma maneira de incorporar totalmente a variável, sem usar qualquer memória?
Muito parecido com o que o pré-processador faz.
Isso exigiria de alguma forma:
Relacionado:
Testado em Ubuntu 18.10, GCC 8.2.0.
fonte
Sim, ele esconde uma variável em um módulo de outros módulos. Em C ++, eu o uso quando não quero / preciso alterar um arquivo .h que irá acionar uma reconstrução desnecessária de outros arquivos. Além disso, coloco a estática primeiro:
Além disso, dependendo de seu uso, o compilador nem mesmo aloca armazenamento para ele e simplesmente "inline" o valor onde é usado. Sem a estática, o compilador não pode assumir que não está sendo usado em outro lugar e não pode embutir.
fonte
Esta é uma constante global visível / acessível apenas no módulo de compilação (arquivo .cpp). BTW, o uso de estático para essa finalidade está obsoleto. É melhor usar um namespace anônimo e um enum:
fonte
enum
tem neste contexto. Cuidado ao elaborar? Talenums
geralmente só são utilizados para evitar o compilador de alocar qualquer espaço para o valor (embora compiladores modernos não precisam destaenum
corte para ele) e para evitar a criação de ponteiros para o valor.Torná-lo privado ainda significa que ele aparece no cabeçalho. Eu tendo a usar a maneira "mais fraca" que funciona. Veja este artigo clássico de Scott Meyers: http://www.ddj.com/cpp/184401197 (é sobre funções, mas pode ser aplicado aqui também).
fonte