web-dev-qa-db-fra.com

Fonction en ligne C99 dans le fichier .c

J'ai défini ma fonction en .c (sans déclaration d'en-tête) comme ici:

inline int func(int i) {
 return i+1;
}

Puis dans le même fichier ci-dessous je l'utilise:

...
i = func(i);

Et pendant la liaison, j'ai eu "une référence indéfinie à 'func'". Pourquoi?

36
user14416

Le modèle inline en C99 est un peu différent de ce que la plupart des gens pensent, et en particulier différent de celui utilisé par C++

inline n'est qu'un indice tel que le compilateur ne se plaint pas des symboles doublement définis. Il ne garantit pas qu'une fonction est en ligne, ni réellement qu'un symbole est généré, si nécessaire. Pour forcer la génération d'un symbole, il faudrait ajouter une sorte d'instanciation après la définition inline:

int func(int i);

Habituellement, vous auriez la définition inline dans un fichier d'en-tête, qui est ensuite inclus dans plusieurs fichiers .c (unités de compilation). Et vous auriez seulement la ligne ci-dessus dans exactement l'une des unités de compilation. Vous ne voyez probablement que le problème que vous rencontrez car vous n'utilisez pas l'optimisation pour l'exécution de votre compilateur.

Donc, votre cas d'utilisation d'avoir le inline dans le fichier .c n'a pas beaucoup de sens, mieux vaut simplement utiliser static pour cela, même un inline supplémentaire ne le fait pas vous acheter beaucoup.

43
Jens Gustedt

La sémantique en ligne C99 est souvent mal comprise. Le spécificateur inline a deux fonctions:

Tout d'abord, comme indice de compilation en cas de static inline et extern inline déclarations. La sémantique reste inchangée si vous supprimez le spécificateur.

Deuxièmement, dans le cas de inline (c'est-à-dire sans static ou extern) brut, fournir une définition en ligne comme alternative à une définition externe, qui doit être présente dans une autre unité de traduction. Ne pas fournir l'externe est un comportement non défini, qui se manifestera normalement comme un échec de liaison.

Cela est particulièrement utile si vous souhaitez placer une fonction dans une bibliothèque partagée, mais aussi rendre le corps de la fonction disponible pour l'optimisation (par exemple, en ligne ou spécialisation). En supposant un compilateur suffisamment intelligent, cela vous permet de récupérer de nombreux avantages des modèles C++ sans avoir à passer par des cercles de préprocesseur.

Notez que c'est un peu plus compliqué que ce que j'ai décrit ici car avoir une autre déclaration externe non en ligne de portée de fichier déclenchera le premier cas comme décrit dans la réponse de Jens, même si la définition elle-même est inline au lieu de extern inline. Ceci est voulu par la conception afin que vous puissiez avoir une seule définition inline dans un fichier d'en-tête, que vous pouvez inclure dans le fichier source qui fournit l'externe en ajoutant une seule ligne pour la déclaration externe.

32
Christoph

Cela est dû à la façon dont GCC gère la fonction inline. GCC effectue la substitution en ligne dans le cadre de l'optimisation.

Pour supprimer cette erreur, utilisez static avant inline. static mot-clé force le compilateur à utiliser le mot-clé statique force le compilateur à prendre cette fonction en ligne qui fait que le programme se compile avec succès.

static inline int func(int i) {
 return i+1;
}
...
i = func(i);
0
Niloy Rashid