12
votes

Taille de comportement de façon inattendue

Considérez le code suivant:

  #include <stdio.h>
  int main(void)
  {
    int a[10];
    printf("%d",(int)sizeof(a)); //prints 10*sizeof(int) (40 on my compiler)
    printf("%d",(int)sizeof(a-3)); //prints sizeof(int) (4 on my compiler)

  }

c

2 commentaires

Le second imprime en fait tailleOf (int *) , pas Tailleof (int) . Tailleof (int *) Il se trouve que 4 aussi sur votre plate-forme.


En outre, la manière appropriée d'imprimer une valeur taille_t (la valeur renvoyée par Tailleof ) est avec "% zu" , en supposant que votre compilateur prend en charge fonctionnalité de C99 particulière. Sinon, un meilleur pari serait de le jeter à un non signé ou non signé long .


4 Réponses :


5
votes

(A-3) a type int * et il vous imprime Tailleof (int *) qui est sur votre plate-forme.

et note que tailleOf () n'est plus une constante de temps de compilation en C99 (en raison des réparations de longueur variable).


1 commentaires

Pour être clair - le résultat de Tailleof n'est pas une constante de temps de compilateur uniquement lorsque l'opérande est un tableau de longueur variable. Il est toujours une constante pour les autres types d'opérande.



1
votes

NOPE, dans le second cas, l'argument est interprété comme un pointeur int * ayant également une taille égale à 4 sur votre machine.


0 commentaires

30
votes

Le Taille de l'opérateur n'évalue pas son argument, il uniquement regarde le type de son opérande.

Disons que vous avez un tableau A avec type "Array [N] de type T". Ensuite, dans la plupart des cas, le type du nom A est "pointeur sur t" ( t * ) et la valeur du pointeur est l'adresse du premier élément de la matrice ( & a [0] ). C'est-à-dire que le nom d'un tableau "se désintègre" à un pointeur à son premier élément. Le "décomposition" ne se produit pas dans les cas suivants:

  • Lorsque A est utilisé avec l'opérateur Adresse du ( & ),
  • dans l'initialisation de A (il est illégal d'attribuer aux tableaux en C) et
  • Quand a est l'opérande de la taille de opérateur.

    donc, Taille de A vous donne N fois Tailleof (t) .

    quand vous DO TAILLEOF (A-3) , Type de l'opérande à TAILLEOF est déterminé par l'expression A-3 . Étant donné que A dans A-3 est utilisé dans un Contexte de la valeur (c.-à-d. Aucun des trois contextes ci-dessus), son type est" pointeur à int ", et le nom A décrit sur un pointeur sur A [0] . En tant que tel, calculer A-3 est un comportement non défini, mais étant donné que Tailleof n'évalue pas son argument, A-3 est utilisé uniquement pour déterminer Le type de l'opérande, le code est donc correct (voir le premier lien ci-dessus pour plus).

    de ce qui précède, Tailleof (A-3) est équivalent à Tailleof (int *) , qui est 4 sur votre ordinateur.

    La "conversion" est due à l'opérateur de soustraction. Vous pouvez voir un résultat similaire et peut-être plus surprenant avec l'opérateur de la virgule: xxx

    imprimera également Tailleof (int *) , à cause de L'opérateur de la virgule qui aboutit à a est utilisé dans un contexte de valeur.


0 commentaires

1
votes

tailleOf () renvoie la taille d'un type, de sorte que le type est ce qui est important.

Il ne doit pas non plus être imprimé avec % d . À tout le moins, le jetez explicitement à non signé long ou non signé long long et utilisez le spécificateur de format approprié. Lors de l'enseignement C, j'ai eu un étudiant obtenu la mauvaise réponse en impression Taille_t avec % d car le manuel dit à tort à tort.

Quoi qu'il en soit, A est un type de tableau. Dans C, les types de tableau sont décomposés aux types de pointeur si vous faites presque n'importe quoi avec eux ou éternuez fort, donc tout ce que vous faites pour A donnera un type de pointeur. Comme vous l'avez découvert, l'ajout ou la soustraction d'un numéro se décomposira. (Après tout, un tableau ne peut pas être utilisé en arithmétique, mais un pointeur peut.)


3 commentaires

@David: Tant que le résultat ne déborde pas, si on jette l'expression comme (int) , puis l'imprimez avec "% d" est correct. Dans ce cas, il est presque certain que la taille correspondra à un int . En C99, on utiliserait "% zu" bien sûr. Pour C89, votre suggestion est meilleure que l'impression avec "% d" après la mise en moulage comme (int) car il est plus sujeux de débordement.


@Alok: True, mais le casting est beaucoup plus important que ce que vous lancez. En outre, je connais très bien le C89 et je n'ai pas utilisé C99, et cela montre probablement.


L'OP a la distribution dans sa question. Je suis d'accord avec vous - sans le casting, "% d" est faux, mais le document printf () de l'OP () est ok aussi longtemps qu'il n'y a pas de débordement.