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
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 :
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).
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
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
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".
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
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...
In article <eqs5g6$pkq$1@s1.news.oleane.net>,
Falk Tannhäuser <falk.tannhauser@crf.canon.fr> 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...
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...
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
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:james.kanze@gmail.com
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
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.).
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.).
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.).
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".
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".
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
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
Marc Espie schrieb:
In article <eqs5g6$pkq$1@s1.news.oleane.net>,
Falk Tannhäuser <falk.tannhauser@crf.canon.fr> 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".
À 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".