Extrait de code (simplifié) donné:

void foo(int a, int b); // declaration with prototype

int main(void)
{
    foo(1, 5); // type-checked call (i.e. because of previous prototype)
    return 0;
}

void foo() // old-style definition (with empty argument list)
{

}

Et les options de ligne de commande (cependant, comme je l'ai vérifié, elles ne sont pas importantes):

-x c -std=c11 -pedantic -Wall

Gcc 7.2 ne parvient pas à le compiler avec le message d'erreur suivant:

erreur: le nombre d'arguments ne correspond pas au prototype

Tandis que clang 4.0 le traduit sans aucune plainte.

Quelle implémentation est correcte selon la norme C? Est-il valide que la définition à l'ancienne "annule" le prototype précédent?

17
Grzegorz Szpetkowski 29 août 2017 à 21:01

2 réponses

(C11, 6.7p4 Contraintes) "Toutes les déclarations dans le même domaine d'application qui se réfèrent au même objet ou fonction doivent spécifier des types compatibles"

Et

(C11, 6.7.6.3p14) "Une liste d'identificateurs ne déclare que les identificateurs des paramètres de la fonction. Une liste vide dans un déclarateur de fonction qui fait partie d'une définition de cette fonction spécifie que la fonction n'a pas de paramètres. [.. .] "

Mon avis est que la contrainte de 6.7p4 est violée et qu'un diagnostic doit être émis.

MODIFIER:

Comme l'a souligné @hvd, ce n'est en fait pas correct. 6.7.6.3p14 ne signifie pas que void foo() {} fournit un prototype pour foo selon DR # 317. En ce sens, la contrainte 6.7p4 n'est pas violée et donc clang a raison de ne pas se plaindre.

15
ouah 30 août 2017 à 08:33

De la norme C (6.7.6.3 Déclarateurs de fonction (y compris les prototypes))

15 Pour que deux types de fonctions soient compatibles, les deux doivent spécifier des types de retour compatibles.146) De plus, ... Si un type a une liste de types de paramètres et l'autre type est spécifié par une définition de fonction qui contient une liste d'identificateurs (éventuellement vide) , les deux doivent s'accorder sur le nombre de paramètres, et le type de chaque paramètre prototype doit être compatible avec le type qui résulte de l'application de l'argument par défaut promotions au type de l'identifiant correspondant. (Dans la détermination de la compatibilité de type et d'un type composite, chaque paramètre déclaré avec un type de fonction ou de tableau est considéré comme ayant le type ajusté et chaque paramètre déclaré avec un type qualifié est considéré comme ayant la version non qualifiée de son type déclaré.)

Et (6.2.7 Type compatible et type composite)

2 Toutes les déclarations qui se réfèrent au même objet ou fonction doivent avoir un type compatible; sinon, le comportement n'est pas défini

Ainsi, le programme montré dans la question a un comportement indéfini. Le compilateur peut émettre un message de diagnostic comme l'a fait GCC.

7
Vlad from Moscow 29 août 2017 à 18:24