Qu’est-ce qu’une unité de traduction en C?

La définition couramment utilisée d’une unité de traduction est ce qui vient après le prétraitement (inclusions de fichiers d’en-tête, macros, etc. avec le fichier source). Cette définition est raisonnablement claire et la norme C, 5.1.1.1, C11, dit:

Programme AC n’a pas besoin d’être tous traduits en même temps. Le texte du programme est conservé dans des unités appelées fichiers sources (ou fichiers de prétraitement) dans la présente Norme internationale. Un fichier source avec tous les en-têtes et les fichiers source inclus via la directive de prétraitement #include est appelé une unité de traduction de prétraitement. Après le prétraitement, une unité de traduction de prétraitement est appelée unité de traduction.

En lisant la première phrase de plus près:

Programme AC n’a pas besoin d’être tous traduits en même temps.

ce qui implique (à ma lecture), un programme C peut être traduit en même temps sans nécessairement les diviser en plusieurs fichiers sources de prétraitement. Toujours à la fin du même paragraphe, la norme dit:

Les unités de traduction peuvent être traduites séparément et ensuite liées pour produire un programme exécutable.

qui peut être (et est généralement) interprété comme la compilation de fichiers object individuels, puis enfin les reliant pour produire un seul programme exécutable. Toutefois, si l’on peut poser une question à partir de la déclaration ci-dessus et poser une question: cela signifie-t-il qu’une implémentation est libre de considérer plusieurs fichiers source comme une seule unité de traduction, en particulier pour une invocation telle que:

 gcc file1.c file2.c -o out 

où le compilateur a access à la source entière?

En particulier, si une implémentation traite file1.c + file2.c (ci-dessus) comme une unité de traduction unique, peut-elle être considérée comme non conforme?

Dans la deuxième ligne, vous avez cité:

Le texte du programme est conservé dans des unités appelées fichiers sources (ou fichiers de prétraitement) dans la présente Norme internationale.

S’il existe deux fichiers sources, il existe deux fichiers de prétraitement, et donc deux unités de traduction en cours de prétraitement, et donc deux unités de traduction. Un correspondant à chaque fichier source.

La norme ne définit pas le fichier source . J’imagine que le compilateur pourrait dire “je crée ma propre version de ‘fichier source’ en déclarant que file1.c et file2.c ne sont pas des fichiers sources après tout!” et les concaténer, mais cela irait à l’encontre des attentes des programmeurs. Je pense que vous auriez du mal à faire valoir que file1.c n’est pas un fichier source.

Toutefois, si vous pouvez poser une question à partir de la déclaration ci-dessus et poser la question suivante: une implémentation est-elle libre de considérer plusieurs fichiers source comme une seule unité de traduction

Non, la définition est claire:

Un fichier source avec tous les en-têtes et les fichiers source inclus via la directive de prétraitement #include est appelé une unité de traduction de prétraitement. Après le prétraitement, une unité de traduction de prétraitement est appelée unité de traduction.

Une unité de traduction est le résultat du prétraitement d’ un fichier source et de ses inclus. Le fait que vous puissiez traduire deux unités de traduction en même temps ne signifie pas que vous pouvez les traiter comme une seule unité de traduction.

Les compilateurs sont libres de traduire plusieurs fichiers sources en même temps, mais ils ne peuvent pas changer leur sémantique.

Traduire plusieurs fichiers ensemble sera probablement un peu plus rapide (car le compilateur ne démarre qu’une seule fois) et permettra une meilleure optimisation de l’ensemble du programme: le code source des fonctions appelées dans d’autres unités de traduction est alors disponible au moment de l’appel à partir d’autres unités de traduction. Le compilateur peut inspecter le code appelé et utiliser les informations, autant que possible avec une seule unité de traduction. Depuis le manuel de gcc 6.3.0:

Le compilateur effectue une optimisation en fonction de la connaissance du programme. La compilation de plusieurs fichiers à la fois en un seul mode de sortie permet au compilateur d’utiliser les informations obtenues à partir de tous les fichiers lors de la compilation de chacun d’entre eux.

Les fonctions appelées peuvent être inspectées pour vérifier l’absence d’alias, la constance factuelle des objects pointés, etc., ce qui permet au compilateur d’effectuer des optimisations qui seraient erronées dans le cas général.

Et, bien sûr, de telles fonctions peuvent être intégrées.

Mais il existe des sémantiques d’unités de traduction (prétraitement) (correspondant aux fichiers source après prétraitement, selon votre devis standard) que le compilateur doit respecter. @ Malcolm en a mentionné une, les variables statiques-fichiers. Mon intuition est qu’il peut y avoir d’autres problèmes, plus subtils, concernant les déclarations et l’ordre des déclarations.

Un autre problème évident lié à la scope du code source définit. À partir du projet de n1570, 6.10.3.5:

Une définition de macro dure (indépendamment de la structure de bloc) jusqu’à ce qu’une directive #undef correspondante soit rencontrée ou (si aucune n’est rencontrée) jusqu’à la fin de l’unité de traduction en cours de prétraitement.

Les deux problèmes interdisent la concaténation simple de fichiers source C; le compilateur doit en outre appliquer une logique rudimentaire.

Une unité de traduction signifie un fichier point C. À toutes fins utiles, y compris son point associé h inclut. Rarement, les directives #include sont utilisées pour append d’autres types de fichiers ou d’autres fichiers C.

les variables statiques ne sont visibles que dans l’unité de traduction. Il est très courant de disposer de quelques fonctions publiques avec une liaison externe et de nombreuses fonctions statiques et éléments de données pris en charge. Ainsi, une unité de traduction C est un peu comme une classe C ++ singleton. Si le compilateur ne gère pas correctement la fonction statique, il est non conforme.

En règle générale, un fichier object est créé pour chaque unité de traduction. Ils sont ensuite liés par l’éditeur de liens. Ce n’est pas prévu par la norme, c’est le moyen naturel et évident de faire des choses dans un environnement où la création de fichiers est peu coûteuse et où la compilation est relativement lente.