Manière standard de trouver l’adresse de base de la structure à partir d’un membre

struct Data { int a; std::ssortingng b; float c; }; std::ssortingng* allocateDataAndGetSsortingng() { Data* dataPtr(someAllocator.allocate()); return &dataPtr.b; } Data* getBaseDataPtrFromSsortingng(std::ssortingng* mSsortingngMember) { // ??? } int main() { std::ssortingng* ssortingngPtr(allocateDataAndGetSsortingng()); Data* dataPtr(getBaseDataPtrFromSsortingng } 

J’ai une instance de Data allouée sur le tas et un pointeur sur son std::ssortingng b; membre. Comment obtenir l’adresse de base de l’instance de Data la chaîne est membre, en tenant compte des décalages et du remplissage, de manière standard?

J’ai essayé de soustraire sizeof(int) et std::offsetof(Data, std::ssortingng) du pointeur std::ssortingng* , mais je n’ai pas réussi à le faire fonctionner.

Utilisez offsetof partir de , mais attention, il est uniquement défini sur les types de disposition standard ( Live at Coliru ):

 Data* getBaseDataPtrFromSsortingng(std::ssortingng* mSsortingngMember) { static_assert(std::is_standard_layout::value, "offsetof() only works on standard-layout types."); return reinterpret_cast( reinterpret_cast(mSsortingngMember) - offsetof(Data, b) ); } 

offsetof est détaillé dans C ++ 11 18.2 / 4:

La macro offsetof ( type , membre-désignateur ) accepte un ensemble limité d’arguments de type dans la présente Norme internationale. Si type n’est pas une classe de disposition standard (clause 9), les résultats ne sont pas définis. 195 L’expression offsetof ( type , membre-désignateur ) n’est jamais dépendante du type (14.6.2.2) et dépend de la valeur (14.6.2.3) si et seulement si le type est dépendant. Le résultat de l’application de la macro offsetof à un champ qui est un membre de données statique ou un membre de fonction n’est pas défini. Aucune opération invoquée par la macro offsetof ne doit offsetof une exception et noexcept(offsetof(type, member-designator)) doit être true .

et C99 (N1256) 7.17 / 3:

Les macros sont

 NULL 

qui se développe en une constante de pointeur null définie par la mise en oeuvre; et

 offsetof(type, member-designator) 

qui se développe en une expression constante entière de type size_t , dont la valeur est le décalage en octets, vers la structure membre (désignée par le membre-indicateur ), à partir du début de sa structure (désignée par le type ). Le type et le désignateur de membre doivent être tels que

 static type t; 

alors l’expression &(t. membre-désignateur ) évaluée à une adresse constante. (Si le membre spécifié est un champ de bits, le comportement n’est pas défini.)

Le “jeu limité d’arguments de type dans la présente Norme internationale” dans la norme C ++ est destiné à attirer votre attention sur le fait que offsetof est plus ressortingctif que pour la norme C.

offsetof donne le décalage en caractères, il est donc nécessaire de mSsortingngMember en caractère char * avant de procéder à l’arithmétique du pointeur.

 (Data*)((char*)mSsortingngMember - offsetof(Data, b)) 

offsetof ne fonctionne que sur les types de disposition standard.

Il existe une astuce que vous pourriez être en mesure d’utiliser et qui n’exige pas de présentation standard: static_cast sait comment accéder à un object plus dérivé à partir d’un pointeur sur l’une de ses bases.

 struct Data : private std::ssortingng { private: using b_base = std::ssortingng; public: // was int f() const { return b.size(); } int f() const { return b_base::size(); } private: int a; float c; friend Data* getBaseDataPtrFromSsortingng(std::ssortingng* mSsortingngMember); }; Data* getBaseDataPtrFromSsortingng(std::ssortingng* mSsortingngMember) { return static_cast(mSsortingngMember); } 

Si vous êtes certain que ptr est en fait l’adresse de s->b (ce qui n’est pas toujours vrai), vous pouvez essayer d’utiliser offsetof :

 Data* getBaseDataPtrFromSsortingng(std::ssortingng* ptr) { void* ad = (char*)ptr - offsetof(Data,b); return reinterpret_cast(ad); } 

En passant, GCC a intégré un offset pour aider à implémenter la macro offsetof (notamment dans des cas plus généraux que ceux requirejs par la norme). Voir cette question .