Question

En quoi cette syntaxe C est-elle utile: vous utilisez des déclarations de fonction de style 'K & R'?

int func (p, p2)
    void* p;
    int  p2;
{
    return 0;
}

J'ai pu écrire cela dans Visual Studios 2010beta

// yes, the arguments are flipped
void f()
{
    void* v = 0;
    func(5, v);
}

Je ne comprends pas. Quel est le point de cette syntaxe? Je peux écrire:

int func (p, p2)
    int  p2;
{
    return 0;
}
// and write
int func (p, p2)
{
    return 0;
}

La seule chose qu'il semble spécifier est le nombre de paramètres utilisés et le type de retour. Je suppose que les paramètres sans types sont plutôt cool, mais pourquoi l’autoriser et le int paranName après le déclarateur de fonction? C'est bizarre.

Est-ce aussi encore standard C?

Était-ce utile?

La solution

La question que vous posez est en réalité deux questions, pas une. À ce jour, la plupart des réponses ont tenté de couvrir l’ensemble du problème avec une couverture générique "c’est du style K & R". répondez, alors qu’en fait, seule une petite partie de celle-ci a un rapport avec ce que l’on appelle le style K & R (à moins que vous ne voyiez le langage C dans son ensemble comme "style K & R" d’une manière ou d’une autre:)

La première partie est la syntaxe étrange utilisée dans la fonction definition

int func(p, p2)
void *p;
int  p2; /* <- optional in C89/90, but not in C99 */
{
  return 0;
}

Celui-ci est en réalité une définition de fonction de style K & R. Autre réponse ont assez bien couvert cela. Et en réalité, il n'y a pas grand chose. La syntaxe est obsolète, mais toujours pleinement prise en charge, même en C99 (à l'exception de la règle "no implicit int" en C99, ce qui signifie qu'en C99, vous ne pouvez pas omettre la déclaration de p2 ).

La deuxième partie a peu à voir avec le style K & R. Je me réfère au fait que la fonction peut être appelée avec "swappé". arguments, c’est-à-dire qu’aucune vérification du type de paramètre n’a lieu dans un tel appel. Cela a très peu à voir avec la définition de style K & R en soi, mais cela a tout à voir avec votre fonction n'ayant pas de prototype. Vous voyez, en C quand vous déclarez une fonction comme celle-ci

int foo();

il déclare en fait une fonction foo qui prend un nombre non spécifié de paramètres de type inconnu . Vous pouvez l'appeler comme

foo(2, 3);

et comme

j = foo(p, -3, "hello world");

ans et ainsi de suite (vous voyez l'idée);

Seul l'appel avec les arguments appropriés va "travailler". (signifiant que les autres produisent un comportement indéfini), mais il vous incombe entièrement de vous assurer de son exactitude. Le compilateur n’est pas obligé de diagnostiquer les valeurs incorrectes même s’il connaît magiquement les types de paramètres corrects et leur nombre total.

En fait, ce comportement est une fonctionnalité du langage C. Un dangereux, mais une fonctionnalité néanmoins. Cela vous permet de faire quelque chose comme ça

void foo(int i);
void bar(char *a, double b);
void baz(void);

int main()
{
  void (*fn[])() = { foo, bar, baz };
  fn[0](5);
  fn[1]("abc", 1.0);
  fn[2]();
}

i.e. mélanger différents types de fonctions dans un "polymorphe" tableau sans typecasts (les types de fonctions variadiques ne peuvent cependant pas être utilisés ici). Encore une fois, les dangers inhérents à cette technique sont assez évidents (je ne me souviens pas de l’avoir utilisée, mais je peux imaginer où elle peut être utile), mais c’est tout de même C après tout.

Enfin, le bit qui relie la deuxième partie de la réponse à la première. Lorsque vous définissez une définition de fonction de style K & R, elle n'introduit pas de prototype pour la fonction. En ce qui concerne le type de fonction, votre définition func déclare que func est

.
int func();

i.e. ni les types ni le nombre total de paramètres ne sont déclarés. Dans votre message d'origine, vous dites "... il semble spécifier le nombre de paramètres qu'il utilise ...". Formellement parlant, ça ne marche pas! Après votre définition de func à deux paramètres de style K & R, vous pouvez toujours appeler func en tant que

.
func(1, 2, 3, 4, "Hi!");

et il n'y aura pas de violation de contrainte. (Normalement, un compilateur de qualité vous avertira).

En outre, un fait parfois négligé est que

int f()
{
  return 0;
}

est également une définition de fonction de style K & R qui n'introduit pas de prototype. Pour le rendre "moderne" vous devez mettre un void explicite dans la liste de paramètres

int f(void)
{
  return 0;
}

Enfin, contrairement à une idée reçue, les définitions de fonctions de style K & R et les déclarations de fonctions non prototypées sont entièrement prises en charge dans C99. Le premier est obsolète depuis C89 / 90, si je me souviens bien. C99 exige que la fonction soit déclarée avant la première utilisation, mais il n'est pas nécessaire que la déclaration soit un prototype. La confusion semble provenir de la confusion terminologique populaire: beaucoup de gens appellent n'importe quelle déclaration de fonction "un prototype", alors qu'en réalité "la déclaration de fonction" n’est pas la même chose que le "prototype".

Autres conseils

Il s’agit d’une ancienne syntaxe K & amp; C (antérieure à ANSI / ISO C). De nos jours, vous ne devriez plus l'utiliser (car vous avez déjà remarqué son inconvénient majeur: le compilateur ne vérifiera pas les types d'arguments pour vous). Le type d'argument par défaut est int dans votre exemple.

À l'époque, cette syntaxe était utilisée, on trouvait parfois des fonctions comme

foo(p, q) 
{
    return q + p;
}

qui était en fait une définition valide, comme les types pour foo , p et q par défaut à int .

Il s'agit simplement d'une ancienne syntaxe, antérieure à "ANSI C". syntaxe que vous connaissez peut-être mieux. C'est ce qu'on appelle " K & amp; RC " ;, typiquement.

Les compilateurs estiment qu'il est complet et qu'il est capable de gérer les anciennes bases de code, bien sûr.

Il s'agit de la syntaxe K & R originale avant la normalisation de C en 1989. C89 a introduit les prototypes de fonctions empruntés à C ++ et déconseillé la syntaxe K & R. Il n'y a aucune raison de l'utiliser (et de nombreuses raisons de ne pas le faire) dans le nouveau code.

C’est une relique de l’époque où C n’avait plus de prototypes pour ses fonctions. À l'époque, (je pense), les fonctions étaient supposées renvoyer int et tous ses arguments étaient supposés être int . Aucune vérification n'a été effectuée sur les paramètres de la fonction.

Vous feriez bien mieux d'utiliser des prototypes de fonctions dans le langage C actuel.
Et vous devez les utiliser en C99 (C89 accepte toujours l'ancienne syntaxe).

Et C99 exige que les fonctions soient déclarées (éventuellement sans prototype). Si vous écrivez une nouvelle fonction à partir de zéro, vous devez fournir une déclaration ... faites-en aussi un prototype: vous ne perdez rien et obtenez une vérification supplémentaire du compilateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top