45 votes

C: Pourquoi les pointeurs non affectés pointent-ils vers une mémoire imprévisible et ne pointent-ils pas vers NULL?

Il y A longtemps que j'ai utilisé pour programmer en C pour l'école. Je me souviens de quelque chose que je détestais vraiment sur le C: non attribué pointeurs ne pointent pas vers NULL.

J'ai demandé à beaucoup de gens, y compris les enseignants, pourquoi dans le monde feraient-ils le comportement par défaut d'un pointeur non affecté non point à la valeur NULL comme il semble beaucoup plus dangereux pour elle d'être imprévisible.

La réponse a été soi-disant de la performance, mais je n'ai jamais acheté que. Je pense que beaucoup de beaucoup de bugs dans l'histoire de la programmation aurait pu être évitée si C par défaut à NULL.

Voici quelques code C pour le point (pun intended) de quoi je parle:

#include <stdio.h>

void main() {

  int * randomA;
  int * randomB;
  int * nullA = NULL;
  int * nullB = NULL;


  printf("randomA: %p, randomB: %p, nullA: %p, nullB: %p\n\n", 
     randomA, randomB, nullA, nullB);
}

Qui compile avec des avertissements (c'est agréable de voir les compilateurs C sont beaucoup plus beau quand j'étais à l'école) et les sorties:

randomA: 0xb779eff4, randomB: 0x804844b, nullA: (néant), nullB: (néant)

42voto

ninjalj Points 22026

En fait, cela dépend du stockage du pointeur. Les pointeurs avec stockage statique sont initizalized avec des pointeurs null. Les pointeurs automatique de la durée de stockage ne sont pas initialisés. Voir ISO C 99 6.7.8.10:

Si un objet qui a automatique de la durée de stockage n'est pas initialisé explicitement, sa valeur est durée indéterminée. Si un objet statique de la durée de stockage n'est pas initialisé explicitement, alors:

  • si elle est de type pointeur, il est initialisé à un pointeur null;
  • si c'est de l'arithmétique, il est initialisé à (positif ou non signé) zéro;
  • si c'est un agrégat, chaque membre est initialisé (de manière récursive) selon les présentes règles;
  • si c'est une union, le premier nommé membre est initialisé (de manière récursive) selon ces règles.

Et oui, les objets automatique de la durée de stockage ne sont pas initialisés pour des raisons de performances. Imaginez l'initialisation d'un 4K tableau sur chaque appel à une fonction d'enregistrement (ce que j'ai vu sur un projet, j'ai travaillé sur, heureusement C permettez-moi d'éviter l'initialisation, résultant en une belle performance boost).

26voto

detly Points 11267

Parce que, dans C, de déclaration et d'initialisation sont délibérément différentes étapes. Ils sont délibérément différent parce que c'est la façon dont C est conçu.

Quand vous dites ce à l'intérieur d'une fonction:

void demo(void)
{
    int *param;
    ...
}

Vous dites: "mon cher compilateur C, lorsque vous créez le cadre de pile pour cette fonction, n'oubliez pas de réserver sizeof(int*) octets pour stocker un pointeur." Le compilateur ne pas demander ce qui se passe là - il suppose que vous allez dire à bientôt. Si vous ne le faites pas, il existe peut-être un meilleur langage pour vous ;)

Peut-être qu'il ne serait pas diaboliquement difficile de générer de la sécurité de la pile de compensation de code. Mais il faudrait être appelé à chaque appel de fonction, et je doute que beaucoup de développeurs C apprécierait de les frapper quand ils vont juste pour le remplir eux-mêmes de toute façon. D'ailleurs, il y a beaucoup de choses que vous pouvez faire pour les performances si vous êtes autorisé à être flexible avec la pile. Par exemple, le compilateur peut faire de l'optimisation...

Si votre function1 en appelle un autre function2 et stocke sa valeur de retour, ou peut-être il ya certains paramètres passés en function2 qui ne sont pas modifiées à l'intérieur d' function2... nous n'avons pas à créer de l'espace supplémentaire, n'avons-nous? Suffit d'utiliser la même partie de la pile pour les deux! Notez que cela est en conflit direct avec le concept de l'initialisation de la pile avant chaque utilisation.

Mais dans un sens plus large, (et à mon avis, plus important encore) qu'il est aligné avec C la philosophie de ne pas faire beaucoup plus que ce qui est absolument nécessaire. Et cela s'applique si vous travaillez sur un PDP11, un PIC32MX (ce que j'utilise pour) ou un Cray XT3. C'est exactement pourquoi les gens pourraient choisir d'utiliser le C à la place des autres langues.

  • Si je veux écrire un programme sans trace d' malloc et free, je n'ai pas à! Pas de gestion de la mémoire est imposé à moi!
  • Si je veux bits-pack et le type de jeu de données de l'union, je peux! (Tant que j'ai lu de mise en œuvre de notes sur la norme de respect, bien sûr.)
  • Si je sais exactement ce que je fais avec mon frame de pile, le compilateur n'a pas à faire autre chose pour moi!

En bref, lorsque vous demandez le compilateur C pour sauter, il ne demande pas à quelle hauteur. Le code résultant ne sera probablement même pas redescendre.

Comme la plupart des gens qui choisissent de développer en C, comme de cette façon, il a assez d'inertie pour ne pas changer. Votre façon peut-être pas intrinsèquement mauvaise idée, c'est juste pas vraiment demandé par de nombreux autres développeurs C.

14voto

David Sykes Points 9683

C'est pour la performance.

C a été développé pour la première fois à l’époque du PDP 11, pour lequel 60k était la quantité de mémoire maximale commune, beaucoup en auraient eu beaucoup moins. Les affectations inutiles seraient particulièrement coûteuses dans ce type d'environnement

De nos jours, de nombreux périphériques embarqués utilisent le C pour lequel 60 ko de mémoire sembleraient infinis, le PIC 12F675 en possède un.

9voto

Mr. kbok Points 4374

C'est parce que lorsque vous déclarez un pointeur, votre C compilateur de réserver l'espace nécessaire pour la mettre. Ainsi, lorsque vous exécutez votre programme, cette espace peut déjà avoir une valeur, résultant probablement d'un précédent de données alloué sur cette partie de la mémoire.

Le compilateur C pourrait attribuer cet indicateur une valeur, mais ce serait une perte de temps dans la plupart des cas, puisque vous êtes à l'exception d'attribuer une valeur personnalisée-vous dans une certaine partie du code.

C'est pourquoi les bons compilateurs donner un avertissement lorsque vous n'avez pas initialiser vos variables; donc je ne pense pas qu'il y a tellement de bugs à cause de ce comportement. Vous avez juste à lire les mises en garde.

8voto

caf Points 114951

Les pointeurs ne sont pas spéciaux à cet égard; les autres types de variables ont exactement le même problème si vous les utilisez sans initialisation:

 int a;
double b;

printf("%d, %f\n", a, b);
 

La raison est simple: demander à l'exécution de définir des valeurs non initialisées sur une valeur connue ajoute une surcharge à chaque appel de fonction. La surcharge peut ne pas être beaucoup avec une seule valeur, mais considérez si vous avez un grand tableau de pointeurs:

 int *a[20000];
 

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