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?
Remarque: Cette réponse s'applique au langage C, pas à C++.
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.
'\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. ").
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.
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.
Tous trois définissent la signification de zéro dans un contexte différent.
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.
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
et0
sont interchangeables dans des contextes de pointeur, et qu'un uncast0
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 pointeurs0
des entiers0
.Ce n'est que dans les contextes de pointeur que
NULL
et0
sont équivalents.NULL
ne doit pas être utilisé lorsqu'un autre type de0
est requis, même si cela peut fonctionner, car cela envoie un message stylistique erroné. (En outre, ANSI permet que la définition deNULL
soit((void *)0)
, ce qui ne fonctionnera pas du tout dans des contextes sans pointeur.) En particulier, n'utilisez pasNULL
lorsque le ASCII caractère NULL (NUL
) souhaité. Fournissez votre propre définition
#define NUL '\0'
si tu dois.
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 ++.
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.
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.
"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.
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
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.