web-dev-qa-db-fra.com

Pourquoi ce code segfault sur l'architecture 64 bits mais fonctionne bien sur 32 bits?

Je suis tombé sur le puzzle C suivant:

Q: Pourquoi le programme suivant se bloque-t-il sur IA-64, mais fonctionne-t-il correctement sur IA-32?

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }

Je sais que la taille de int sur une machine 64 bits peut ne pas être la même que la taille d'un pointeur (int pourrait être 32 bits et le pointeur pourrait être 64 bits). Mais je ne sais pas comment cela se rapporte au programme ci-dessus. Des idées?

107
user7

Le transtypage en int* Masque le fait que sans le #include Approprié, le type de retour de malloc est supposé être int. IA-64 se trouve avoir sizeof(int) < sizeof(int*) ce qui rend ce problème évident.

(Notez également qu'en raison du comportement non défini, il peut toujours échouer même sur une plate-forme où sizeof(int)==sizeof(int*) est vraie, par exemple si la convention d'appel utilise des registres différents pour renvoyer des pointeurs que des entiers)

comp.lang.c FAQ a une entrée discutant pourquoi la conversion du retour de malloc n'est jamais nécessaire et potentiellement mauvaise .

124
Flexo

Très probablement parce que vous êtes non compris le fichier d'en-tête pour malloc et, bien que le compilateur vous en avertisse normalement, le fait que vous convertissez explicitement la valeur de retour signifie que vous dis-lui que tu sais ce que tu fais.

Cela signifie que le compilateur s'attend à ce qu'un int soit renvoyé de malloc qu'il convertit ensuite en un pointeur. S'ils sont de tailles différentes, cela vous causera du chagrin.

C'est pourquoi vous jamais transformez le retour malloc en C. Le void* qu'il retourne sera implicitement converti en un pointeur du type correct (à moins que vous n'ayez pas inclus l'en-tête, auquel cas il vous aurait probablement averti de la conversion int-pointer-to-pointer potentiellement dangereuse).

31
paxdiablo

C'est pourquoi vous ne compilez jamais sans avertissements sur les prototypes manquants.

C'est pourquoi vous ne lancez jamais le retour malloc en C.

Le cast est nécessaire pour la compatibilité C++. Il y a peu de raisons (lire: aucune raison ici) de l'omettre.

La compatibilité C++ n'est pas toujours nécessaire, et dans certains cas pas possible du tout, mais dans la plupart des cas, elle est très facilement réalisée.

9
curiousguy