115 votes

Pourquoi le compilateur ne signale-t-il pas un point-virgule manquant?

J'ai ce programme simple:

#include <stdio.h>

struct S
{
    int i;
};

void swap(struct S *a, struct S *b)
{
    struct S temp;
    temp = *a    /* Oops, missing a semicolon here... */
    *a = *b;
    *b = temp;
}

int main(void)
{
    struct S a = { 1 };
    struct S b = { 2 };

    swap(&a, &b);
}

Comme on le voit par exemple sur ideone.com cela donne une erreur:

prog.c: In function 'swap':
prog.c:12:5: error: invalid operands to binary * (have 'struct S' and 'struct S *')
     *a = *b;
     ^

Pourquoi ne pas le compilateur de détecter le point-virgule manquant?


Remarque: Cette question et sa réponse est motivée par cette question. Alors qu'il y a d'autres questions semblables à ceci, je n'ai rien trouvé de mention de la capacité du langage C, qui est ce qui est à l'origine de ces erreurs.

225voto

Joachim Pileborg Points 121221

C est une forme libre de la langue. Cela signifie que vous pourriez format dans de nombreuses façons et il sera toujours un programme juridique.

Par exemple, un énoncé comme

a = b * c;

peut être écrite comme

a=b*c;

ou comme

a
=
b
*
c
;

Ainsi, lorsque le compilateur voir les lignes

temp = *a
*a = *b;

il pense que cela veut dire

temp = *a * a = *b;

Cela n'est évidemment pas une expression valide et le compilateur va se plaindre de ce que, au lieu de le point-virgule manquant. La raison pour laquelle il n'est pas valable, c'est parce qu' a est un pointeur sur une structure, de sorte *a * a est d'essayer de multiplier une structure instance (*a) avec un pointeur vers une structure (a).

Alors que le compilateur ne peut pas détecter le point-virgule manquant, il indique également les totalement sans rapport avec l'erreur sur la mauvaise ligne. Il est important de noter parce que peu importe combien vous regardez la ligne où l'erreur est signalée, il n'y a pas d'erreur là. Parfois, des problèmes de ce genre ont besoin de vous pour regarder les précédentes lignes pour voir si ils sont d'accord et sans erreurs.

Parfois, vous avez même de regarder dans un autre fichier pour trouver l'erreur. Par exemple, si un fichier d'en-tête est la définition d'une structure de la dernière dans le fichier d'en-tête, et le point-virgule de résiliation de la structure est manquant, alors l'erreur ne sera pas dans le fichier d'en-tête, mais dans le fichier qui contient le fichier d'en-tête.

Et parfois c'est même pire: si vous incluez les deux (ou plus) fichiers d'en-tête, et le premier contient une déclaration incomplète, probablement l'erreur de syntaxe sera indiqué dans le deuxième fichier d'en-tête.


Lié à cela est le concept de suivi des erreurs. Certaines erreurs, en général, à cause du manque de points-virgules en fait, sont comptabilisés comme des multiples erreurs. C'est pourquoi il est important de commencer par le haut lors de la correction d'erreurs, comme la fixation de la première erreur peut faire plusieurs erreurs disparaissent.

Bien sûr, cela peut conduire à la fixation d'une erreur à un moment et fréquente recompile qui peut être lourd avec de grands projets. La reconnaissance de ces erreurs est quelque chose qui vient avec l'expérience, et après avoir vu quelques fois il est plus facile de creuser le réel les erreurs et les corriger plus d'une erreur par le recompiler.

29voto

plugwash Points 795

Pourquoi ne pas le compilateur de détecter le point-virgule manquant?

Il y a trois choses à retenir.

  1. Les fins de ligne dans C ne sont que de simples espaces.
  2. * en C peut être à la fois un unaire et binaire de l'opérateur. Comme un opérateur unaire, il signifie "déréférencement", comme un opérateur binaire, cela signifie "se multiplier".
  3. La différence entre les opérateurs unaires et binaires est déterminée à partir du contexte dans lequel ils apparaissent.

Le résultat de ces deux faits, c'est quand nous analyser.

 temp = *a    /* Oops, missing a semicolon here... */
 *a = *b;

Le premier et le dernier * sont interprétés comme unaire, mais le second * est interprété comme binaire. À partir d'un point de vue de la syntaxe, cela semble OK.

C'est seulement après l'analyse lorsque le compilateur tente d'interpréter les opérateurs dans le cadre de leurs opérandes de types qu'une erreur s'est vu.

4voto

Mawg Points 7387

Quelques bonnes réponses ci-dessus, mais je vais élaborer.

 temp = *a *a = *b;
 

C'est en fait un cas de x = y = z;x et y voient attribuer la valeur de z .

Ce que vous dites, c'est the contents of address (a times a) become equal to the contents of b, as does temp .

En bref, *a *a = <any integer value> est une déclaration valide. Comme indiqué précédemment, le premier * déréférence un pointeur, tandis que le second multiplie deux valeurs.

3voto

supercat Points 25534

La plupart des compilateurs analyser les fichiers source dans l'ordre, et le rapport de la ligne où ils découvrent que quelque chose n'allait pas. Les 12 premières lignes de votre programme C peut être le début d'un valide (erreur) C programme. Les 13 premières lignes de votre programme ne peut pas. Certains compilateurs notez l'emplacement des choses qu'ils rencontrent qui ne sont pas des erreurs dans et d'eux-mêmes, et dans la plupart des cas ne se déclenche pas d'erreurs plus tard dans le code, mais peut ne pas être valable en combinaison avec autre chose. Par exemple:

int foo;
...
float foo;

La déclaration int foo; par elle-même serait parfaitement bien. De même, la déclaration float foo;. Certains compilateurs peuvent enregistrer le numéro de ligne où la première déclaration est apparu, et d'associer un message d'information avec cette ligne, pour aider le programmeur à identifier les cas où la définition est en fait erronée. Les compilateurs peut aussi conserver les numéros de ligne associé à quelque chose comme un do, qui peut être déclarée que si les associés while n'apparaît pas dans le bon endroit. Pour les cas où l'emplacement probable du problème serait précédant immédiatement la ligne où l'erreur est découverte, cependant, les compilateurs n'ont généralement pas la peine d'ajouter un supplément de rapport pour le poste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X