Quelle est la raison d’être des définitions provisoires en C?

Pensez au programme suivant. Est-ce que cela donnera des erreurs de compilation?

#include  int s=5; int s; int main(void) { printf("%d",s); } 

À première vue, il semble que le compilateur générera une erreur de redéfinition variable, mais le programme est parfaitement valide conformément au standard C. (Voir la démonstration en direct ici http://ideone.com/Xyo5SY ).

Une définition provisoire est toute déclaration de données externe qui n’a pas de spécificateur de classe de stockage ni d’initialiseur.

C99 6.9.2 / 2

La déclaration d’un identifiant pour un object ayant une scope de fichier sans initialiseur, et sans spéci fi cateur de classe de stockage ou avec le spéci fi cateur de classe de stockage statique, constitue une définition provisoire. Si une unité de traduction contient une ou plusieurs définitions provisoires pour un identificateur, et que l’unité de traduction ne contient aucune définition externe pour cet identificateur, le comportement est exactement comme si l’unité de traduction contenait une déclaration de la scope du fichier de cet identificateur, avec le type composite de la fin de l’unité de traduction, avec un initialiseur égal à 0.

Ma question est la suivante: quelle est la raison de permettre des définitions provisoires? Est-ce que cela peut être utilisé en C? Pourquoi C autorise-t-il les définitions provisoires?

Les définitions provisoires ont été créées pour permettre de rapprocher les modèles incompatibles qui existaient avant C89. Ceci est traité dans la section 6.9.2 la justification de C99, dans la définition d’object externe qui dit:

Avant C90, les implémentations variaient considérablement en ce qui concernait les identifiants de référence directe avec liaison interne (voir le § 6.2.2). Le comité C89 a inventé le concept de définition provisoire pour gérer cette situation. Une définition provisoire est une déclaration qui peut ou peut ne pas agir en tant que définition: si une définition réelle est trouvée plus tard dans l’unité de traduction, la définition provisoire agit simplement comme une déclaration. Si ce n’est pas le cas, la définition provisoire sert de définition réelle. Par souci de cohérence, les mêmes règles s’appliquent aux identifiants avec liaison externe, bien qu’elles ne soient pas ssortingctement nécessaires.

et la section 6.2.2 de la justification du C99 dit:

Le modèle de définition à utiliser pour les objects avec une liaison externe était un problème majeur de normalisation C89. Le problème de base consistait à décider quelles déclarations d’un object définissaient le stockage de cet object et lesquelles référençaient simplement un object existant. Un problème connexe était de savoir si plusieurs définitions de stockage sont autorisées ou si une seule est acceptable. Les implémentations antérieures à C89 présentent au moins quatre modèles différents , listés ici par ordre croissant de ressortingction:

Voici un exemple de cas où cela est utile:

 void (*a)(); void bar(); void foo() { a = bar; } static void (*a)() = foo; /* ... code that uses a ... */ 

Le point clé est que la définition de foo doit faire référence à a , et la définition de a doit se référer à foo . Des exemples similaires avec des structures initialisées devraient également être possibles.