web-dev-qa-db-fra.com

Quelle est la différence entre NULL, '\ 0' et 0

En C, il semble y avoir des différences entre les différentes valeurs de zéro - NULL, NUL et 0.

Je sais que le caractère ASCII '0' correspond à 48 ou 0x30.

Le pointeur NULL est généralement défini comme suit:

#define NULL 0

Ou

#define NULL (void *)0

De plus, il y a le NUL caractère '\0' qui semble aussi être évalué à 0.

Y a-t-il des moments où ces trois valeurs ne peuvent pas être égales?

Est-ce également vrai sur les systèmes 64 bits?

282
gnavi

Remarque: Cette réponse s'applique au langage C, pas à C++.


Pointeurs nuls

La constante de nombre entier littérale 0 a différentes significations en fonction du contexte dans lequel elle est utilisée. Dans tous les cas, il s'agit toujours d'une constante entière ayant la valeur 0, elle est simplement décrite de différentes manières.

Si un pointeur est comparé à la constante littérale 0, il s'agit alors d'une vérification pour déterminer si le pointeur est un pointeur nul. Cette 0 est alors appelée constante de pointeur nulle. La norme C définit que 0 cast au type void * est à la fois un pointeur nul et une constante de pointeur nul.

De plus, pour améliorer la lisibilité, la macro NULL est fournie dans le fichier d'en-tête stddef.h. En fonction de votre compilateur, il pourrait être possible de #undef NULL et de le redéfinir en quelque chose de farfelu.

Par conséquent, voici quelques moyens valables de rechercher un pointeur null:

if (pointer == NULL)

NULL est défini pour une comparaison égale à un pointeur nul. C'est l'implémentation définie ce qu'est la définition réelle de NULL, tant qu'il s'agit d'une constante de pointeur null valide.

if (pointer == 0)

0 est une autre représentation de la constante du pointeur nul.

if (!pointer)

Cette instruction if vérifie implicitement "n'est pas 0", nous inversons donc pour signifier "est 0".

Voici des méthodes INVALID permettant de rechercher un pointeur null:

int mynull = 0;
<some code>
if (pointer == mynull)

Pour le compilateur, il ne s'agit pas d'un contrôle pour un pointeur null, mais d'un contrôle d'égalité sur deux variables. Cela pourrait fonctionner si mynull ne change jamais dans le code et si l'optimisation du compilateur plie constamment le 0 dans l'instruction if, mais cela n'est pas garanti et le compilateur doit produire au moins un diagnostic. message (avertissement ou erreur) selon la norme C.

Notez que ce qui est un pointeur nul dans le langage C. Peu importe l'architecture sous-jacente. Si l'architecture sous-jacente a une valeur de pointeur null définie en tant qu'adresse 0xDEADBEEF, il appartient au compilateur de résoudre ce problème.

En tant que tel, même sur cette architecture amusante, les méthodes suivantes restent des méthodes valides pour rechercher un pointeur null:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Voici des méthodes INVALID permettant de rechercher un pointeur null:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

comme ceux-ci sont vus par un compilateur comme des comparaisons normales.

Caractères nuls

'\0' est défini comme un caractère nul, c'est-à-dire un caractère dont tous les bits sont mis à zéro. Cela n'a rien à voir avec les pointeurs. Cependant, vous pouvez voir quelque chose de similaire à ce code:

if (!*string_pointer)

vérifie si le pointeur de la chaîne pointe sur un caractère NULL

if (*string_pointer)

vérifie si le pointeur de la chaîne pointe sur un caractère non NULL

Ne confondez pas ces indicateurs avec des pointeurs nuls. Juste parce que la représentation des bits est la même, et que cela permet quelques cas pratiques de croisement, ils ne sont pas vraiment la même chose.

De plus, '\0' est (comme tous les littéraux de caractères) une constante entière, dans ce cas avec la valeur zéro. Donc, '\0' est complètement équivalent à une constante entière 0 sans décors - la seule différence réside dans l’intention qu’elle transmet au lecteur humain ("I ' m en utilisant cela comme un caractère nul. ").

Références

Voir Question 5.3 de la FAQ comp.lang.c pour plus d'informations. Voir this pdf pour le standard C. Consultez les sections 6.3.2.3 Pointeurs, paragraphe 3.

327
Andrew Keeton

Il semble qu'un certain nombre de personnes comprennent mal ce que sont les différences entre NULL, '\ 0' et 0. Donc, pour expliquer, et pour éviter de répéter des choses dites plus tôt:

Une expression constante de type int avec la valeur 0 ou une expression de ce type, convertie en type void * est un constante du pointeur nul, qui, s'il est converti en un pointeur, devient un pointeur nul. Il est garanti par le standard de comparer différent de tout pointeur sur un objet ou une fonction.

NULL est une macro définie en tant que constante du pointeur nul.

'\ 0' est une construction utilisée pour représenter le caractère nul, utilisée pour terminer une chaîne.

Un caractère nul est un octet dont tous les bits sont définis sur 0.

33
amaterasu

Tous trois définissent la signification de zéro dans un contexte différent.

  • contexte de pointeur - NULL est utilisé et signifie que la valeur du pointeur est 0, que ce soit en 32 bits ou en 64 bits (un cas 4 octets les 8 autres octets de zéros).
  • contexte de chaîne - le caractère représentant le chiffre zéro a une valeur hexadécimale de 0x30, tandis que le caractère NUL a une valeur hexadécimale de 0x00 (utilisée pour les chaînes de terminaison).

Ces trois sont toujours différents quand on regarde la mémoire:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

J'espère que cela le clarifie.

14
Nasko

Si NULL et 0 sont équivalents en tant que constantes de pointeur nul, que dois-je utiliser? dans la liste C FAQ adresse également ce problème:

Les programmeurs C doivent comprendre que NULL et 0 sont interchangeables dans des contextes de pointeur, et qu'un uncast 0 est parfaitement acceptable. Toute utilisation de NULL (par opposition à 0) doit être considérée comme un rappel gentil qu’un pointeur est impliqué; Les programmeurs ne doivent pas en dépendre (ni pour leur propre compréhension, ni pour celle du compilateur) pour distinguer les pointeurs 0 des entiers 0.

Ce n'est que dans les contextes de pointeur que NULL et 0 sont équivalents. NULL ne doit pas être utilisé lorsqu'un autre type de 0 est requis, même si cela peut fonctionner, car cela envoie un message stylistique erroné. (En outre, ANSI permet que la définition de NULL soit ((void *)0), ce qui ne fonctionnera pas du tout dans des contextes sans pointeur.) En particulier, n'utilisez pas NULL lorsque le ASCII caractère NULL (NUL) souhaité. Fournissez votre propre définition

#define NUL '\0'

si tu dois.

6
Sinan Ünür

Quelle est la différence entre NULL, ‘\ 0’ et 0

"Caractère nul (NUL)" est le plus facile à exclure. '\0' est un littéral de caractère. En C, il est implémenté sous la forme int, il est donc identique à 0, ce qui correspond à INT_TYPE_SIZE. En C++, le littéral de caractère est implémenté sous la forme char, ce qui correspond à 1 octet. Ceci est normalement différent de NULL ou 0.

Ensuite, NULL est une valeur de pointeur qui spécifie qu'une variable ne pointe pas vers un espace d'adressage. Mis à part le fait qu'il est généralement implémenté sous forme de zéros, il doit être capable d'exprimer tout l'espace d'adressage de l'architecture. Ainsi, sur une architecture 32 bits, la valeur NULL (probable) est de 4 octets et celle de l'architecture 64 bits, de 8 octets. Ceci est à la mise en œuvre de C.

Enfin, le littéral 0 est de type int, de taille INT_TYPE_SIZE. La valeur par défaut de INT_TYPE_SIZE peut être différente selon l'architecture.

Apple a écrit:

Le modèle de données 64 bits utilisé par Mac OS X est appelé "LP64". Il s'agit du modèle de données commun utilisé par d'autres systèmes UNIX 64 bits de Sun, SGI et Linux 64 bits. Le modèle de données LP64 définit les types de primitive comme suit:

  • les ints sont 32 bits
  • longs sont 64 bits
  • longs-longs sont également 64 bits
  • les pointeurs sont en 64 bits

Wikipedia 64-bit :

Le compilateur VC++ de Microsoft utilise le modèle LLP64.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

Edit : Ajout de plus sur le caractère littéral.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

Le code ci-dessus renvoie 4 sur gcc et 1 sur g ++.

5
Eugene Yokota

Un NUL, il termine une chaîne.

Deux NUL ne signale rien.

Et je parierai un taureau d'or

Qu'il n'y a pas trois-L NULLL.

Comment traitez-vous avec NUL?

4
EvilTeach

Un bon morceau qui m'aide au démarrage avec C (Tiré de la programmation Expert C de Linden)

Le 'l' nul et les Deux 'l' null

Mémorisez cette petite comptine pour rappeler la terminologie correcte pour les pointeurs et ASCII zéro:

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 

Le caractère ASCII avec le motif de bits de zéro est appelé "NUL". La valeur spéciale du pointeur qui signifie que le pointeur ne pointe nulle part est "NULL". Les deux termes ne sont pas interchangeables dans leur signification.

4
dlmeetei

"NUL" n'est pas 0, mais fait référence au caractère ASCII NUL. Au moins, c'est comme ça que je l'ai vu utilisé. Le pointeur null est souvent défini sur 0, mais cela dépend de l'environnement dans lequel vous vous trouvez et de la spécification du système d'exploitation ou de la langue que vous utilisez.

En ANSI C, le pointeur NULL est défini sur la valeur entière 0. Ainsi, tout monde dans lequel ce n'est pas vrai n'est pas conforme à ANSI C.

2
peterb

Il n'est pas garanti que NULL soit 0 - sa valeur exacte dépend de l'architecture. La plupart des grandes architectures le définissent comme (void*)0.

'\0' sera toujours égal à 0, car c'est ainsi que l'octet 0 est codé dans un littéral de caractère.

Je ne me souviens pas s'il est nécessaire que les compilateurs C utilisent ASCII - sinon '0' ne correspond pas toujours à 48. Quoi qu'il en soit, il est peu probable que vous rencontriez un système utilisant une alternative. jeu de caractères comme EBCDIC sauf si vous travaillez sur des systèmes très obscurs.

Les tailles des différents types seront différentes sur les systèmes 64 bits, mais les valeurs entières seront les mêmes.


Certains commentateurs ont émis des doutes sur le fait que NULL soit égal à 0, mais pas be zéro. Voici un exemple de programme, avec les résultats attendus sur un tel système:

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

Ce programme pourrait imprimer:

NULL == 0
NULL = 0x00000001
0
John Millikin

Un octet de valeur 0x00 correspond, sur la table ASCII, au caractère spécial appelé "NUL" ou "NULL". En C, étant donné que vous ne devez pas incorporer de caractères de contrôle dans votre code source, cela est représenté dans les chaînes C avec un 0 d'échappement, c'est-à-dire "\ 0".

Mais un vrai NULL est pas une valeur. C'est l'absence de valeur. Pour un pointeur, cela signifie que le pointeur n'a rien à pointer. Dans une base de données, cela signifie qu'il n'y a pas de valeur dans un champ (ce qui n'est pas la même chose que de dire que le champ est vide, 0 ou rempli d'espaces).

La valeur réelle utilisée par un format de fichier système ou de base de données donné pour représenter une valeur NULL n'est pas nécessairement 0x00.

0
richardtallent