OVH Cloud OVH Cloud

Buffer alignée

12 réponses
Avatar
Guillaume GOURDIN
Bonjour à tous,

petit question: comment écririez-vous une fonction testant si un pointer
est aligné sur 16 octets ?

Merci !

10 réponses

1 2
Avatar
Falk Tannhäuser
Guillaume GOURDIN wrote:
petit question: comment écririez-vous une fonction testant si un pointer
est aligné sur 16 octets ?


En théorie, la Norme ne fournit pas de moyens portables pour faire ce
test, mais en pratique, ceci fera l'affaire :

bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}

Falk

Avatar
Sylvain Togni
Falk Tannhäuser wrote:

En théorie, la Norme ne fournit pas de moyens portables pour faire ce
test, mais en pratique, ceci fera l'affaire :

bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}


À quoi sert le volatile ?

--
Sylvain Togni

Avatar
Michael DOUBEZ
Falk Tannhäuser wrote:

En théorie, la Norme ne fournit pas de moyens portables pour faire ce
test, mais en pratique, ceci fera l'affaire :

bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;



Ou encore:
return (reinterpret_cast<unsigned long long>(p)&0x0f==0);

}


À quoi sert le volatile ?



Ici, le volatile ne sert à rien.
En général, ça indique au processeur de ne pas bufferiser la valeur
pointée (pour les accès à des registres par exemple).

Michael


Avatar
Falk Tannhäuser
Sylvain Togni wrote:
Falk Tannhäuser wrote:
bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}
À quoi sert le volatile ?



Ça permet d'appeler cette fonction avec un pointeur qualifié 'volatile',
ce qui me semble potentiellement utile quand on fait de la programmation
"bas niveau".

Falk


Avatar
espie
In article <eqs5g6$pkq$,
Falk Tannhäuser wrote:
Sylvain Togni wrote:
Falk Tannhäuser wrote:
bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}
À quoi sert le volatile ?



Ça permet d'appeler cette fonction avec un pointeur qualifié 'volatile',
ce qui me semble potentiellement utile quand on fait de la programmation
"bas niveau".


Bof, bof, bof.

Moi je regarde mon code de noyau, je n'y vois pas tant de volatile que ca,
et pourtant c'est de la programmation bas-niveau.

Je regarde le malloc de ma libc, je n'y vois aucun volatile, et pourtant
il est rempli de manipulations de pointeurs.

En fait, il y a plein d'algo qui manipulent directement des adresses memoire
qui sont extremement utiles (dans des circonstances particulieres, soit)
et qui pour autant ne vont pas discuter directement avec le materiel...

Je dirais meme plus, meme dans du code systeme bas niveau, volatile est
l'exception plutot que la norme...



Avatar
James Kanze
Marc Espie wrote:

[...]
Je dirais meme plus, meme dans du code systeme bas niveau, volatile est
l'exception plutot que la norme...


D'autant plus que la plupart des compilateurs n'en génèrent pas
ce qu'il faut pour que l'accès au bas niveau fonctionne,
n'est-ce pas ?

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Mathias Gaunard
Guillaume GOURDIN wrote:
petit question: comment écririez-vous une fonction testant si un
pointer est aligné sur 16 octets ?


En théorie, la Norme ne fournit pas de moyens portables pour faire ce
test, mais en pratique, ceci fera l'affaire :

bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}


Pourquoi unsigned long ?
size_t devrait mieux faire l'affaire.


Avatar
Falk Tannhäuser
Mathias Gaunard schrieb:
bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;
}


Pourquoi unsigned long ?
size_t devrait mieux faire l'affaire.


size_t n'est pas forcement assez grand pour contenir la valeur d'un
pointeur, donc j'imagine que la compilation pourrait échouer sur les
plate-formes concernées - § 5.2.10/4 dit "A pointer can be explicitly
converted to any integral type large enough to hold it...". Ceci a
notamment été le cas sur les plate-formes 16 bits Intel x86, où size_t
était un typedef pour "unsigned" qui faisait 16 bits, tandis que les
pointeurs pouvaient faire 32 bits dans certains circonstances (aaah le
bon vieux temps des "memory models" et autres "__near", "__far" et
"__huge" ...).
Avec "unsigned long" la garantie n'existe pas non plus, mais les chances
que ça passe sont plus grandes (au moins c'était OK sur l'Intel 16 bits)
et avec "unsigned long long" (comme proposé dans ce fil) on devrait être
peinard pour un bon moment (à condition d'utiliser un compilo pas trop
vieux quand même - "[unsigned] long long" a été normalisé en C99 et ne
le sera en C++ que dans la prochaine version de la Norme, attendue vers
2008...2010).
C99 semble aussi connaître les typedefs "uintptr_t" et "intptr_t" (de
façon optionnelle dans <stdint.h>) qui font exactement ce qu'on veut -
espérons qu'on les aura bientôt en C++ (dans <cstdint>, namespace std
S.V.P.).

Falk


Avatar
Falk Tannhäuser
Michael DOUBEZ schrieb:
Falk Tannhäuser wrote:
bool is_aligned16(void const volatile* p)
{
return reinterpret_cast<unsigned long>(p) % 16 == 0;



Ou encore:
return (reinterpret_cast<unsigned long long>(p)&0x0f==0);


Avec la parenthèse fermante là où il faut car le "==" est plus
prioritaire que le "&" (sinon "0x0f==0" donne "false", donc la fonction
ne risque guère renvoyer "true", quelque soit "p")

Sinon je serais étonné de voir un compilateur moderne générant un code
différent, voir moins bon pour la version avec "% 16" que pour "& 0x0F".

Falk



Avatar
Falk Tannhäuser
Marc Espie schrieb:
In article <eqs5g6$pkq$,
Falk Tannhäuser wrote:
Sylvain Togni wrote:
À quoi sert le volatile ?
Ça permet d'appeler cette fonction avec un pointeur qualifié 'volatile',

ce qui me semble potentiellement utile quand on fait de la programmation
"bas niveau".
[...]


Je dirais meme plus, meme dans du code systeme bas niveau, volatile est
l'exception plutot que la norme...


C'est vrai, le terme "programmation bas niveau" n'est pas le plus
précis, j'avais en tête les accès à des registres du matériel mappés
dans la mémoire ou à des zones de mémoire ou il y a des accès DMA - dans
ce cas-là, le "volatile" s'avère souvent nécessaire (mais pas forcement
suffisant comme le fait remarquer James - on peut aussi être amené de
jouer avec la cache ou les membar...). En dehors de cela, il est vrai
que "volatile" ne sert que rarement, même dans du code "système". Par
contre, je ne sais pas dans quel domaine la fonction en question est
censée servir et je trouverais dommage de ne pas pouvoir l'employer sur
un pointeur "volatile" sans utiliser de cast, d'autant plus qu'ici le
"volatile" est sans incidence sur la taille et rapidité de code généré,
le pointeur en question n'étant jamais déréférencé.
Rappelons que selon § 4.4/1 il existe une conversion implicite d'un
"pointeur vers cv1 T" vers un "pointeur vers cv2 T" lorsque "cv2 T" a
d'avantage de qualificateurs "const/volatile" que "cv1 T" (par exemple
un "void*" est convertible de façon implicite en "void volatile*" tout
comme en "void const*" et "void const volatile*"), la fonction pourra
donc servir également avec des pointeurs sans qualification
"const/volatile", ou seulement "const" ou "volatile".

Falk



1 2