Qual é a diferença entre a função "estática" e "estática em linha"?

123

A IMO cria a função de ter apenas um escopo da unidade de tradução.

Qual é a diferença entre a função "estática" e "estática em linha"?

Por que deve inlineser colocado em um arquivo de cabeçalho, não em um .carquivo?

new_perl
fonte

Respostas:

109

inlineinstrui o compilador a tentar incorporar o conteúdo da função no código de chamada em vez de executar uma chamada real.

Para pequenas funções chamadas com freqüência que podem fazer uma grande diferença de desempenho.

No entanto, isso é apenas uma "dica", e o compilador pode ignorá-la, e a maioria dos compiladores tentará "incorporar" mesmo quando a palavra-chave não for usada, como parte das otimizações, sempre que possível.

por exemplo:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Esse loop restrito executará uma chamada de função em cada iteração, e o conteúdo da função é realmente significativamente menor que o código que o compilador precisa colocar para executar a chamada. inlineessencialmente instruirá o compilador a converter o código acima em um equivalente a:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Ignorando a chamada de função real e retornando

Obviamente, este é um exemplo para mostrar o ponto, não um pedaço de código real.

staticrefere-se ao escopo. Em C, significa que a função / variável só pode ser usada dentro da mesma unidade de conversão.

littleadv
fonte
4
Não, staticrefere-se ao escopo. Em C, significa que a função / variável só pode ser usada dentro da mesma unidade de conversão.
Littleadv
8
Também é importante observar que o código declarado como inline pertence ao cabeçalho, onde o código-fonte normal (sem modelo) não pode entrar nos cabeçalhos sem causar vários erros de redefinição. Assim, mesmo quando declarar algo em linha, mesmo que os escolhe compilador não para inline-lo, ainda há um comportamento evitando-múltipla redefinição mandatado-padrão que entra em ação.
VoidStar
13
@VoidStar Na verdade static(com ou sem inline) pode estar no cabeçalho perfeitamente, não vejo razão para não. Modelos é para C ++, esta questão é de cerca de C.
littleadv
2
@littleadv: a principal razão para colocar definições de funções em arquivos de cabeçalho é torná-los elegíveis para uso inline, então marcá-los explicitamente inlineé bom estilo, imo
Christoph
9
Na verdade inline, não instrui o compilador a fazer tentativas de inclusão. Apenas permite que o programador inclua o corpo da função em várias unidades de tradução sem violação do ODR. Um efeito colateral disso é que é torna possível para o compilador, quando ele iria inline função, para realmente fazer isso.
Ruslan
96

Por padrão, uma definição embutida é válida apenas na unidade de tradução atual.

Se a classe de armazenamento for extern, o identificador possui ligação externa e a definição embutida também fornece a definição externa.

Se a classe de armazenamento for static, o identificador possui ligação interna e a definição embutida é invisível em outras unidades de conversão.

Se a classe de armazenamento não for especificada, a definição em linha será visível apenas na unidade de conversão atual, mas o identificador ainda possui ligação externa e uma definição externa deve ser fornecida em uma unidade de conversão diferente. O compilador é livre para usar a definição interna ou externa se a função for chamada na unidade de tradução atual.

Como o compilador é livre para incorporar (e não incorporar) qualquer função cuja definição seja visível na unidade de tradução atual (e, graças às otimizações do tempo do link, mesmo em unidades de tradução diferentes, embora o padrão C não seja realmente responsável por que), para fins mais práticos, não há diferença entre statice static inlinedefinições de função.

O inlineespecificador (como a registerclasse de armazenamento) é apenas uma dica do compilador, e o compilador é livre para ignorá-lo completamente. Os compiladores não otimizadores compatíveis com os padrões precisam apenas honrar seus efeitos colaterais, e os otimizadores compiladores farão essas otimizações com ou sem dicas explícitas.

inlinee registernão são inúteis, no entanto, pois instruem o compilador a gerar erros quando o programador escreve código que tornaria as otimizações impossíveis: Uma inlinedefinição externa não pode fazer referência a identificadores com ligação interna (pois eles não estavam disponíveis em uma unidade de tradução diferente) ou defina variáveis ​​locais modificáveis ​​com duração de armazenamento estático (como elas não compartilhariam o estado nas unidades de conversão) e você não poderá obter endereços de registervariáveis ​​qualificadas.

Pessoalmente, também uso a convenção para marcar staticdefinições de função nos cabeçalhos inline, pois o principal motivo para colocar definições de função nos arquivos de cabeçalho é torná-las inlináveis.

Em geral, eu apenas uso definições de static inlinefunção e static constobjeto, além de externdeclarações nos cabeçalhos.

Eu nunca escrevi uma inlinefunção com uma classe de armazenamento diferente de static.

Christoph
fonte
8
Essa é a resposta correta. Qualquer resposta falando inlinecomo se realmente fosse aplicada a inlining é enganosa e indiscutivelmente incorreta. Nenhum compilador moderno o utiliza como uma dica para incorporar ou requerê-lo, a fim de permitir a inclusão de uma função.
Tyg13
1
voto positivo para "use a convenção para marcar definições de função estática nos cabeçalhos inline".
John Z. Li
21

Pela minha experiência com o GCC, sei disso statice static inlinedifere de uma maneira como o compilador emite avisos sobre funções não utilizadas. Mais precisamente, quando você declara a staticfunção e ela não é usada na unidade de tradução atual, o compilador produz um aviso sobre a função não utilizada, mas você pode inibi-lo alterando-o para static inline.

Portanto, costumo pensar que isso staticdeve ser usado em unidades de tradução e se beneficiar do compilador de verificação extra para encontrar funções não utilizadas. E static inlinedeve ser usado em arquivos de cabeçalho para fornecer funções que podem ser alinhadas (devido à ausência de ligação externa) sem emitir avisos.

Infelizmente, não consigo encontrar nenhuma evidência para essa lógica. Mesmo na documentação do GCC, não consegui concluir que inlineinibe avisos de funções não utilizados. Eu apreciaria se alguém compartilhar links para a descrição disso.

ony
fonte
Mmm, ainda recebi warning: unused function 'function' [clang-diagnostic-unused-function]uma static inlinefunção ao criar com clang-tidy(v8.0.1), que é usado em outra unidade de tradução. Mas, definitivamente, esta é uma das melhores explicações e razões para combinar o static& inline!
DrumM 29/04
6

Em C, staticsignifica que a função ou variável que você define pode ser usada apenas neste arquivo (ou seja, a unidade de compilação)

Portanto, static inlinesignifica a função embutida que pode ser usada apenas neste arquivo.

EDITAR:

A unidade de compilação deve ser a unidade de tradução

shengy
fonte
2
Ou em palavras sofisticadas: possui ligação interna.
precisa
@AlokSave: Existe alguma diferença entre a unidade de compilação e a unidade de tradução ? Em caso afirmativo, qual é o mais apropriado no contexto da linguagem C ++?
Legends2k
Eu acredito que the compile unité algo que eu escrevi no erro, não existe tal coisa, a terminologia real étranslation unit
shengy
Sua resposta não está completa porque é usada principalmente em arquivos de cabeçalho, nas unidades de tradução.
DrumM
5

Uma diferença que não está no nível do idioma, mas no nível de implementação popular: certas versões do gcc removerão static inlinefunções não referenciadas da saída por padrão, mas manterão staticfunções simples mesmo que não sejam referenciadas. Não tenho certeza a quais versões isso se aplica, mas, do ponto de vista prático, significa que pode ser uma boa idéia sempre usar inlinepara staticfunções em cabeçalhos.

R .. GitHub PARE DE AJUDAR O GELO
fonte
Que tal usar inlineem definição? Você também implica não usá-lo para externfunções?
New_perl 14/10
Isso ainda é verdade com a versão recente do GCC? Sua resposta seria muito mais interessante se você der um exemplo e listar a versão do GCC que faz isso.
Z Higgs
@ Zboson: Não tenho essas informações prontamente disponíveis e não tenho tempo para configurar e testar muitas versões do gcc no momento, mas concordo que seria uma informação útil. Você provavelmente poderia descobrir quando o gcc começou a otimizar funções / objetos estáticos não utilizados, examinando o histórico attribute((used))e seu uso para permitir que o asm faça referência a staticfunções e dados não referenciados .
R .. GitHub Pare de ajudar o gelo