6.7.4 Especificadores de função
Um novo recurso do C99: a inline
palavra-chave, adaptada do C ++, é um especificador de função que pode ser usado apenas em declarações de função. É útil para otimizações de programa que requerem a definição de uma função para ficar visível no local de uma chamada. (Observe que o Padrão não tenta especificar a natureza dessas otimizações.)
A visibilidade é garantida se a função tiver vinculação interna, ou se houver vinculação externa e a chamada estiver na mesma unidade de tradução da definição externa. Nesses casos, a presença da inline
palavra -
chave em uma declaração ou definição da função não tem efeito além de indicar uma preferência de que as chamadas dessa função devem ser otimizadas em preferência às chamadas de outras funções declaradas sem oinline
palavra chave.
A visibilidade é um problema para uma chamada de uma função com vínculo externo, onde a chamada está em uma unidade de tradução diferente da definição da função. Neste caso, oinline
palavra chave permite que a unidade de tradução que contém a chamada também contenha uma definição local ou embutida da função.
Um programa pode conter uma unidade de tradução com uma definição externa, uma unidade de tradução com uma definição embutida e uma unidade de tradução com uma declaração, mas sem definição para uma função. As chamadas na última unidade de tradução usarão a definição externa normalmente.
Uma definição embutida de uma função é considerada uma definição diferente da definição externa. Se uma chamada para alguma função func
com vínculo externo ocorre onde uma definição inline é visível, o comportamento é o mesmo como se a chamada fosse feita para outra função, digamos
__func
, com vínculo interno. Um programa em conformidade não deve depender de qual função é chamada. Este é o modelo embutido no padrão.
Um programa em conformidade não deve depender da implementação usando a definição embutida, nem pode confiar na implementação usando a definição externa. O endereço de uma função é sempre o endereço correspondente à definição externa, mas quando esse endereço é usado para chamar a função, a definição embutida pode ser usada. Portanto, o exemplo a seguir pode não se comportar conforme o esperado.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Visto que a implementação pode usar a definição embutida para uma das chamadas saddr
e usar a definição externa para a outra, a operação de igualdade não tem garantia de avaliação para 1 (verdadeiro). Isso mostra que os objetos estáticos definidos na definição embutida são distintos de seus objetos correspondentes na definição externa. Isso motivou a restrição até mesmo contra a definição de umaconst
objeto desse tipo.
Inlining foi adicionado ao padrão de forma que possa ser implementado com a tecnologia de vinculação existente, e um subconjunto de inlining C99 é compatível com C ++. Isso foi conseguido exigindo que exatamente uma unidade de tradução contendo a definição de uma função inline seja especificada como aquela que fornece a definição externa para a função. Como essa especificação consiste simplesmente em uma declaração que não inline
contém a palavra - chave ou contém as duas palavras inline
e extern
, ela também será aceita por um tradutor C ++.
Inlining no C99 estende a especificação C ++ de duas maneiras. Primeiro, se uma função for declarada
inline
em uma unidade de tradução, não precisa ser declarada inline
em todas as outras unidades de tradução. Isso permite, por exemplo, uma função de biblioteca que deve ser embutida na biblioteca, mas disponível apenas por meio de uma definição externa em outro lugar. A alternativa de usar uma função de wrapper para a função externa requer um nome adicional; e também pode afetar negativamente o desempenho se um tradutor não fizer a substituição inline.
Em segundo lugar, o requisito de que todas as definições de uma função inline sejam "exatamente iguais" é substituído pelo requisito de que o comportamento do programa não deve depender se uma chamada é implementada com uma definição inline visível, ou a definição externa, de um função. Isso permite que uma definição inline seja especializada para seu uso em uma unidade de tradução específica. Por exemplo, a definição externa de uma função de biblioteca pode incluir alguma validação de argumento que não é necessária para chamadas feitas de outras funções na mesma biblioteca. Essas extensões oferecem algumas vantagens; e os programadores preocupados com a compatibilidade podem simplesmente seguir as regras mais rígidas do C ++.
Note que é não apropriar para implementações de fornecer definições de inline de funções da biblioteca padrão nos cabeçalhos padrão, porque isso pode quebrar algum código legado que redeclares funções da biblioteca padrão após incluindo seus cabeçalhos. A inline
palavra-chave destina-se apenas a fornecer aos usuários uma maneira portátil de sugerir funções embutidas. Como os cabeçalhos padrão não precisam ser portáteis, as implementações têm outras opções ao longo das linhas de:
#define abs(x) __builtin_abs(x)
ou outros mecanismos não portáteis para funções de biblioteca padrão embutidas.