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’expressionoffsetof
( 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 macrooffsetof
à 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 macrooffsetof
ne doitoffsetof
une exception etnoexcept(offsetof(type, member-designator))
doit êtretrue
.
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 questatic 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 .