Pendant que je créais mon propre malloc, j'ai utilisé write pour imprimer une valeur.
Je n'ai aucun problème pour imprimer la valeur, je crée juste une variable char pour stocker mon numéro et l'imprimer, mais je ne Je ne comprends pas pourquoi le casting ne fonctionne pas. Le prototype d'écriture est:
ssize_t write (int fd, const void * buf, size_t count)
Donc je lance mon nombre dans le vide * sans n'importe quel résultat.
int nb = 3; char numb = nb + '0'; write(1, (void *)(nb + '0'), 1); // Display nothing write(1, &numb, 1); // Display 3
Quelqu'un peut expliquer pourquoi la première écriture n'affiche rien?
3 Réponses :
Casting en void * signifie seulement qu'il doit traiter la valeur donnée comme un pointeur de void.
Mais l '"adresse" donnée est 34 +' 0 ', ce qui est évidemment invalide.
Vous devez donner à write un pointeur pour qu'il ne soit pas possible de faire quelque chose comme ça. vous devez stocker la valeur que vous souhaitez imprimer quelque part dans la mémoire et donner un pointeur vers cet emplacement.
Mais (nb + '0') n'a pas d'adresse.
(void *) (nb + '0') tente de déréférencer la mémoire à la valeur réelle de nb + '0' , comme si cette valeur était un adresse. (nb + '0') n'est pas une valeur l, vous ne pouvez donc pas non plus utiliser l'opérateur & dessus. Ce que vous devriez faire est:
Si vous êtes sur un système little-endian (cela semble être le cas d'OP):
char foo = (nb >> (CHAR_BIT * (sizeof(int) - 1))) & 0xff; foo += '0'; write(..., &foo, ...);
Si vous êtes sur un gros système -endian:
nb += '0'; write(..., &nb, ...);
nb est un int . Que pensez-vous que write fasse avec cela?
@melpomene Étant donné que OP a ajouté la valeur numérique de char '0' , je suppose qu'il est conscient de ce qu'il veut écrire en faire
@melpomene cela fonctionne parce que les entiers sont stockés en mémoire en little endian, donc le premier octet en mémoire est (34 + '0'). write ne le traite pas comme un int
Cette réponse est erronée et dépend de l'endian si nb a un type plus grand que char .
@R .. Mise à jour de ma réponse pour tenir compte des systèmes big-endian
@GovindParmar Oui, c'est vrai ... numéro était le caractère ... Je pense que le meilleur moyen est de l'attribuer à un caractère pour être indépendant des problèmes d'endianité.
@Ctx Ne vous sentez pas mal; Je pensais que nb était également un caractère jusqu'à ce que R .. le fasse remarquer
@AsafRosemarin " les entiers sont stockés en mémoire en little endian " - citation nécessaire.
@GovindParmar: Vous venez de réimplémenter la rupture sur big endian avec une logique endian explicite plutôt qu'en lisant le premier octet de int en mémoire. La bonne solution est juste char foo = nb; Mais cela ne résout pas l'objectif d'OP d'éviter une temp.
Oui, mais ce n'est pas un distribution , c'est un littéral composé :
write(1, &(char){nb + '0'}, 1);
ou:
write(1, (char[]){nb + '0'}, 1);
Merci, c'était exactement ce que je cherchais !! :)
(void *) (nb + '0')est un pointeur vers une adresse invalide - je suis surpris qu'il ne segfault.Pourquoi ne vérifiez-vous pas la valeur de retour de
writepour les erreurs?Les appels système @PaulR ne segfault, ils
EFAULT.Merci pour votre réponse ! Puis-je avoir plus d'informations à ce sujet? Pourquoi est-ce un pointeur vers une adresse invalide?
écriture (1, & numb, 1); // Afficher 34- Cela me surprendrait. Surtout s'il imprime deux caractères alors que vous lui avez dit de n'en imprimer qu'un seul.@GregLoupy Vous prenez un entier aléatoire (82 dans ce cas) et vous le convertissez en pointeur. Comment serait-ce une adresse valide?