5 votes

la manière correcte (ou la plus sûre) d'initialiser un pointeur void avec une valeur non nulle ?

Les travaux suivants :

void* p = reinterpret_cast<void*>(0x1000);

Mais il semble "incorrect/non sûr". Par exemple, 0x1000 est un code d'erreur. int et même pas uintptr_t Si je n'ai pas encore trouvé de solution, je pourrais y remédier, mais existe-t-il une méthode de moulage meilleure ou plus sûre ?

5voto

Maxim Yegorushkin Points 29380

0x1000 est un int et même pas uintptr_t Je pourrais résoudre ce problème, mais existe-t-il une méthode plus sûre ou plus efficace pour couler le sang de l'enfant ?

0x1000 es int et dans reinterpret_cast<void*>(0x1000) le compilateur émet une instruction d'extension de signe (le signe est 0 ici) ou une instruction de chargement de registre simple avec un opérande immédiat pour rendre la valeur aussi large que void* .

Pour de nombreuses raisons, le compilateur ne peut pas savoir si 0x1000 représente une adresse valide, il doit donc s'y conformer et supposer que c'est une adresse valide.

Transformation d'entiers représentant des adresses en pointeurs à l'aide de reinterpret_cast est actuellement la pratique en vigueur.

1voto

bolov Points 4005

Vous pouvez créer un pointeur à partir d'un entier avec reinterpret_cast .

Cependant, un pointeur qui ne pointe pas vers un objet existant (ou qui dépasse le dernier élément d'un tableau, un objet étant considéré comme le seul élément d'un tableau imaginaire dans ce but, ou qui est le pointeur nul) a une valeur de pointeur invalide. Le déréférencement est UB et d'autres opérations avec des valeurs de pointeur invalides sont spécifiques à l'implémentation. Vous devez donc vous assurer que votre compilateur autorise les opérations que vous effectuez avec ces pointeurs.

void* p = reinterpret_cast<void*>(0x1000); // invalid pointer,
                                          // operations on it are implementation defined

§6.7.2 Types de composés [basic.compound].

  1. [...] Chaque valeur du type pointeur est l'une des suivantes :

    3.1 - un pointeur vers un objet ou une fonction (on dit que le pointeur pointe vers l'objet ou la fonction), ou

    3.2 - un pointeur au-delà de la fin d'un objet (8.5.6), ou

    3.3 - la valeur du pointeur nul (7.11) pour ce type, ou

    3.4 - une valeur de pointeur invalide

§8.5.1.10 Réinterpréter le cast [expr.reinterpret.cast]

  1. Un pointeur peut être explicitement converti en tout type intégral suffisamment grand pour le contenir. La fonction de conversion est définie par l'implémentation. [...]
  2. Une valeur de type intégral ou de type énumération peut être explicitement convertie en un pointeur. Un pointeur converti en un entier de taille taille suffisante (s'il en existe un sur l'implémentation) et en retour à le même type de pointeur aura sa valeur originale ; les mappages entre les pointeurs et les entiers sont autrement définis par l'implémentation.

Vous êtes autorisé à convertir un entier en pointeur, mais si la valeur du pointeur résultant ne pointe pas vers un objet existant (ou un objet passé), le pointeur résultant a une valeur invalide.

Maintenant, en ce qui concerne ce que vous pouvez faire avec des pointeurs invalides :

§6.6.4 Durée de stockage [basic.stc].

  1. [...] L'orientation à travers une valeur de pointeur invalide et le passage d'une valeur de pointeur invalide à une fonction de désallocation sont indéfinis. indéfini. Toute autre utilisation d'une valeur de pointeur non valide a un comportement défini par l'implémentation 35

35) Certaines implémentations pourraient définir que la copie d'un pointeur invalide invalide provoque une erreur d'exécution générée par le système.


Ce message a été fortement modifié car il était erroné dans ses premières itérations. Je remercie chaleureusement la communauté de m'avoir corrigé et mis au défi.

1voto

einpoklum Points 2893

tl;dr : Vous ne devriez probablement pas faire ça.

Ce qui suit ... semble "incorrect/non sûr" ... existe-t-il une méthode de coulage meilleure/sûre ?

Comme l'a souligné une autre réponse, c'est "incorrect" dans la mesure où le comportement est défini par l'implémentation. En outre, vous utilisez un nombre magique.

Mais le problème n'est pas le casting, je crois. Je doute vraiment que vous ayez besoin d'initialiser un fichier void* variable avec une adresse littérale. Pourquoi ?

  • S'il y a une sorte de valeur typée à cette adresse, alors n'utilisez pas void * mais plutôt un pointeur typé. Même si vous voulez plus tard passer ce pointeur à memset() o memcpy() ou même une fonction de rappel qui prend void * - retarder l'effacement du type.

  • D'où vient ce chiffre ? Vous savez sûrement les chiffres magiques sont mauvais n'est-ce pas ? Eh bien, au moins, utilisez quelque chose comme

      constexpr const uintptr_t sound_card_memory_mapped_buffer_address { 0x1000 };

    cela répond à l'une de vos préoccupations (non uintptr_t ), et il est aussi plus clair à lire, même si vous restez avec un void * :

      void* p = reinterpret_cast<void*>(sound_card_memory_mapped_buffer_address);
  • p est un mauvais choix de nom pour une variable. Renommez-la en fonction de son utilisation.

  • Avez-vous vraiment besoin d'initialiser p du tout ? :

    • Si vous ne l'utilisez pas pour le moment, pourquoi l'initialiser ? Essayez de ne le déclarer que lorsqu'il est sur le point d'être utilisé (voire pas du tout).

    • Si vous êtes sur le point de l'utiliser, pourquoi le déclarer ? Essayez :

          do_something_with(sound_card_memory_mapped_buffer_address);

      et non p en vue.

J'ai manifestement plus de questions que de réponses à vous poser, puisque vous ne nous avez fourni qu'une seule phrase.

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