Question

Configuration

J'ai quelques questions au sujet des promotions d'argument par défaut lors de l'appel d'une fonction dans C. Voici la section 6.5.2.2 "Fonction appelle" paragraphes 6, 7 et 8 de la norme C99 (pdf) (italique ajouté et divisé en listes pour faciliter la lecture):

Paragraphe 6

  
      
  1. Si l'expression qui désigne la fonction appelée a un type ne comprend pas un prototype , les promotions entières sont effectuées sur chaque argument, et les arguments qui ont le type float sont promus à double. Ceux-ci sont appelés promotions argument par défaut .
  2.   
  3. Si le nombre d'arguments ne correspond pas au nombre de paramètres, le comportement est indéfini.
  4.   
  5. Si la fonction est définie avec un type comprend un prototype , et soit le prototype se termine par des points de suspension (, ...) ou les types des arguments après la promotion ne sont pas compatibles avec les types de paramètres, le comportement est indéfini.
  6.   
  7. Si la fonction est définie avec un type ne comprend pas un prototype , et les types des arguments après la promotion ne sont pas compatibles avec celles des paramètres après la promotion, le comportement est indéfini, à l'exception pour les cas suivants:      
        
    • un type promu est un type entier signé, l'autre type est le type promu entier non signé correspondant, et la valeur est représentable dans les deux types;
    •   
    • les deux types sont des pointeurs vers des versions qualifiées ou non qualifiées d'un type de caractère ou void.
    •   
  8.   

Paragraphe 7

  
      
  1. Si l'expression qui désigne la fonction appelée a un type inclut un prototype , les arguments sont implicitement convertis, comme par cession, aux types des paramètres correspondants, en prenant le type de chaque paramètre à la version non qualifiée de son type déclaré.
  2.   
  3. La notation de suspension dans un prototype de fonction declarator provoque la conversion de type d'argument pour arrêter après le dernier paramètre déclaré. Les promotions argument par défaut sont effectués sur des arguments de fuite.
  4.   

Paragraphe 8

  
      
  1. Aucune autre conversions sont effectuées implicitement; en particulier, le nombre et les types d'arguments ne sont pas comparés à ceux des paramètres dans une définition de fonction ne comprend pas un déclarateur prototype de fonction .
  2.   

Qu'est-ce que je sais

  • promotions argument par défaut sont char et short à int / unsigned int et float à double
  • Les arguments optionnels aux fonctions variadique (comme printf) sont soumis aux promotions d'argument par défaut

Pour mémoire, ma compréhension d'un prototype de fonction est la suivante:

void func(int a, char b, float c);  // Function prototype
void func(int a, char b, float c) { /* ... */ }  // Function definition

Question

Je vais avoir une période très difficile groking tout cela. Voici quelques questions que j'ai:

  • Avez-prototypé et le comportement des fonctions non-prototypé diffèrent vraiment beaucoup, comme en ce qui concerne les promotions et les conversions par défaut implicites?
  • Quand les promotions d'argument par défaut se produisent? Est-il toujours? Ou est-ce dans des cas particuliers (comme des fonctions variadique)? Cela dépend-il si une fonction est prototypé?
Était-ce utile?

La solution

de upvoted AProgrammer réponse-ce sont les biens immobiliers.

Pour ceux d'entre vous qui se demandent pourquoi choses sont ainsi: dans les âges sombres avant 1988, il n'y avait pas une telle chose comme un prototype de fonction en C « K & R » classique, et l'argument par défaut promotions ont été instituées, parce que (a) il y avait essentiellement « libre », car il ne coûte pas plus de mettre un octet dans un registre que de mettre un mot dans un registre, et (b) de réduire les erreurs potentielles dans le passage de paramètres. Cette deuxième raison jamais tout à fait coupé, ce qui était la raison pour laquelle l'introduction de prototypes de fonction en ANSI C a été le changement le plus important jamais dans le langage C.

Quant à savoir quand les promotions par défaut kick in: promotions argument par défaut sont utilisés exactement quand le type attendu de l'argument est inconnu qui est-à-dire quand il n'y a pas de prototype ou lorsque l'argument est variadique.

Autres conseils

  • paramètres de fonctions avec un prototype

    (non variadic) sont converties au type correspondant, qui peut être char, short, flotteur.

  • Paramètres aux fonctions sans paramètres prototypes et variadique sont soumis par défaut promotions d'argument.

Si vous définissez une fonction avec un prototype et de l'utiliser sans le versa prototype ou vice et il a des paramètres de type char, short ou flotteur, vous aurez probablement un problème lors de l'exécution. Vous aurez le même genre de problèmes avec des fonctions variadique si le type promu ne correspond pas à ce qui est utilisé lors de la lecture de la liste des arguments.

Exemple 1:. Problème lors de la définition d'une fonction d'un prototype et de l'utiliser sans

definition.c

void f(char c)
{
   printf("%c", c);
}

use.c

void f();

int main()
{
   f('x');
}

peut échouer, car un entier sera passé et la fonction attendre char.

Exemple 2:. Problème lors de la définition d'une fonction sans prototype et de l'utiliser avec une

definition.c

void f(c)
   char c;
{
   printf("%c", c);
}

(C'est une sorte de définition est très ancienne)

use.c

void f(char c);

int main()
{
   f('x');
}

peut échouer car un int est prévu, mais char sera passé.

Note: vous remarque que toutes les fonctions de la bibliothèque standard ont des types qui résultent de promotions par défaut. Donc, ils ne causent pas de problème lors de la transition lorsque des prototypes ont été ajoutés.

Votre confusion découle d'une incompréhension très légère de la terminologie - les déclarations et les définitions peuvent inclure des prototypes (ou non):

void func(int a, char b, float c);

C'est une fonction déclaration qui comprend un prototype.

void func(int a, char b, float c) { /* ... */ }

C'est une fonction définition qui comprend un prototype.

"prototypé" et "non-prototypé" sont les attributs que d'une fonction type , et les déclarations et les définitions introduisent le type de fonction.

Vous pouvez avoir une déclaration sans prototype:

void func();

ou vous pouvez avoir une définition sans prototype (K & R style C):

void func(a, b, c)
    int a;
    char b;
    float c;
{ /* ... */ }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top