OVH Cloud OVH Cloud

De la pertinence d'une phrase

67 réponses
Avatar
Yoxoman
"La valeur d'un tableau est un pointeur vers son premier élément".
(valeur dans le sens rvalue. D'ailleurs ce mot peut-il avoir un autre
sens ?)

On entend souvent des formulations plus ou moins diverses et compliquées
sur cette conversion tableau-pointeur, ce qui fait qu'on a du mal à s'y
retrouver.
On parle par exemple du nom du tableau (alors que si p pointe vers un
tableau, il me semble que *p est également concerné par cette
conversion), ou d'exception sur certains opérateur (& et sizeof, ce qui
n'est pas faux, mais dont la cause semble être le fait que derrière ces
opérateurs, une lvalue n'est pas convertie en rvalue).

Ma question est simple : cette phrase est-elle vraie ?

--
"Yo!"
Martin Heidegger (trad. Terrence Malick)

10 réponses

Avatar
Emmanuel Delahaye
<complement>
... laquelle adresse est une *valeur* valide pour une variable de type
pointeur sur int.
</complement>


Oui, on peut enfoncer des portes ouvertes toute la journée...

--
A+

Emmanuel Delahaye

Avatar
Marc Boyer
Le 31-03-2006, Emmanuel Delahaye a écrit :
1 est il un int ?
On ne peut pas comparer un type et une valeur.



C'était bien le sens de ma remarque.

1 est une expression constante de type int.


Et surtout, ça n'est pas un objet, ni une variable donc.


'expression constante', ça ne te suffit pas ?


C'est la différence entre 'expression litérale' et 'expression
constante' qui me travaille. Mais surtout en pensant à d'autres
langages (C++ surtout) ou une expression peut être constante
mais aussi être une variable.

Tient, en passant, mon compilo gcc accepte (1)
char** p= &("toto");
donc il accepte de prendre l'adresse d'une constante
litérale, et ça me perturbe un peu...

Marc Boyer

(1) il se plaint juste de type incompatibles
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)




Avatar
Antoine Leca
En news:, Yoxoman va escriure:

Aurais-tu un exemple d'identificateurs différents d'un même objet ?


/* toto.c */
extern int tab[64];

/* tutu.c */
extern int tab[64];


Ou encore

extern int CeciEstUnIdentificateurPlusLongQueLaLimiteDeMonCOmpilateur;
extern int CeciEstUnIdentificateurPlusLongQueLaLimiteDeMonCompilateur_32;



Ou aussi

static int tab[64];

int f() {
extern int tab[64];
/*...*/
}


Antoine

Avatar
Jean-Marc Bourguet
Pierre Maurette writes:

Question aux gurus: il me semble évident qu'à partir du moment où
une variable est déclarée, et durant toute sa vie, l'opérateur
adresse renverra toujours la même valeur. Vous confirmez ?


Oui (6.2.4/2 garanti que tout objet a une adresse constante, hors une
variable est un objet nomme -- du moins c'est le sens avec lequel je
l'emploie, je n'ai pas trouve une definition dans la norme.)

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Antoine Leca
En news:, Pierre Maurette va escriure:
Question aux gurus: il me semble évident qu'à partir du moment où une
variable est déclarée, et durant toute sa vie, l'opérateur adresse
renverra toujours la même valeur. Vous confirmez ?


Mettons de côté le fait qu'une variable (un seul objet) peut avoir plusieurs
déclarations, voire même parfois plusieurs définitions (cf. ma réponse à
Yoxoman).

Définis d'abord « même »...

Je pense que si la norme est aussi alambiquée dans ce domaine, par exemple
quand elle dit "[...] shall compare equal" [6.3.2.3p7], c'est qu'il doit
exister des raisons. Dans le même genre, les conditions des opérations ==/! sont différentes de celles de < et compagnie pour les pointeurs (6.5.8 et
6.5.9).

Je peux imaginer par exemple une implémentation où un pointeur est constitué
d'une partie qui est réellement l'adresse (au sens de 3.6, l'indice dans la
carte mémoire du programme), et une autre partie, ignorée lors des
comparaisons, qui dit, /par exemple/, comment a été obtenu le dit pointeur
(partie utilisée par ailleurs dans un ramasse-miettes ou un vérificateur
d'allocation).

Je me souviens même d'un truc Microsoft (breveté je crois) qui utilisait ce
genre d'hypothèse, jouant sur le couple sélecteur+déplacement de l'adressage
en mode réel du x86, en l'occurence pour les callbacks du VMM (WIN386).


Maintenant, cela ne répond pas exactement à ta question (qui semble plus
précise dans son objet), mais j'aurais tendance à penser qu'il faut se
méfier de ce genre « d'évidence ».


Antoine

Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

En news:, Pierre Maurette va escriure:
Question aux gurus: il me semble évident qu'à partir du moment où une
variable est déclarée, et durant toute sa vie, l'opérateur adresse
renverra toujours la même valeur. Vous confirmez ?


Mettons de côté le fait qu'une variable (un seul objet) peut avoir plusieurs
déclarations, voire même parfois plusieurs définitions (cf. ma réponse à
Yoxoman).

Définis d'abord « même »...


Pour info, la definition que j'avais utilisee pour ma reponse etait
"le resultat de == est true".

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Yoxoman

Là, c'est moi qui ne comprend plus rien. Dans le premier cas, p pointe
vers un entier, non ? Tu as bien écrit "int* p", ou c'est mes yeux ? :)


Oui, mais l'entier et le tableau ont la même adresse.
C'est la notion de 'pointe sur' qui n'est pas claire.


Je comprends. Comme je l'ai dit, pour moi « pointeur » est un type. Donc
« p pointe vers un tableau » sous-entend « p est une expression de type
pointeur vers tableau ».
Et pour en revenir à la phrase originale, « la valeur d'un tableau est
un pointeur vers son premier élément » serait formellement « la rvalue
d'une expression de type tableau est une expression de type "pointeur
vers le type du premier élément du tableau", et qui représente l'adresse
(ou le pointeur) du premier élément du tableau ». Ca fait beaucoup de
raccourcis, certes. Mais la question principale des raccourcis
linguistiques n'est-elle pas de savoir si ceux-ci peuvent avoir un sens
erroné ? Et je ne vois pas trop comment on pourrait interpreter celui-là
différemment de sa version formelle.

Dans le premier cas, *p est de type
int, dans l'autre, il est de type int[4].


Oui, modulo 64. Ce que je dis, c'est que *p a une *valeur* (rvalue) de
type pointeur vers int.


Bof... A ce rythme là, il a aussi une valeur de type char*
(modulo sizeof(int)).


Comprends pas.

Oui, mais je dois mal m'exprimer. L'exception d'opérateurs dont je
parle, c'est celle mentionnée dans la faq (via le lien que je t'ai
donné).


Je ne t'accuse absolument pas de ne pas comprendre. Ce que je
dis, c'est que la phrase cité initiallement permet de comprendre
"un peu" ce qui se passe. Mais qu'elle est imprécise.


Ma question initiale portait effectivement principalement sur le sens
des mots. En particulier valeur et pointeur.

*p est de type array-to-T.


typedef int Tab64[64];
Tab64 a;
int* pi= a;
Trab64* pt= &a;

pi est de type pointer-to-int
*pi est de type int
pt est de type pointer-to-array-to-T
*pt est de type array-to-T


Oui. Et ?

Ce dont je parlait ici, c'est des énoncés du type « Whenever we use the
name of an array as a value, that name represents a pointer to the
initial element of the array. » (Accelerated C++).


Sauf avec sizeof et &.


Non. Tout est dans le « as a value ».

Pour moi, pointeur est un type. Ou plutôt un ensemble de types (pointeur
vers T). Je considère « un pointeur » comme synonyme de « une
expression de type pointeur ». Et une rvalue est une expression...


Faut faire attention avec ces raccourcis. Car alors 1 est un int,
et 0.0 un double.


Sans réserve, je dis oui. Même si toi ou ED n'êtes pas d'accord. « 1 est
un int » dans le sens « 1 est une expression (constante) de type int (ou
entier) ». Tout comme

double d; // d est un double
int* p; // p est un pointeur

et qu'une 306, c'est une Peugeot.

Ce singulier-pluriel (*la* valeur ; *ses* cases) peut-il avoir un sens ?
Ou alors la valeur de l'ensemble de ses cases ? Mais je ne sais pas ce
que c'est.


La valeur de l'ensemble de ses cases ? Tu ne vois pas ce que c'est ?


Hmm. Si. Finalement. Comme quoi.

La norme C ne parle pas de rvalue. En note de bas de la page 46, on peut
lire : « What is sometimes called ??rvalue?? is in this International
Standard described as the ??value of an expression??. ».
On lit également (§3.17/1): « value : precise meaning of the contents of
an object when interpreted as having a specific type. ». Mais la norme
du C ne définit pas la « valeur » d'un tableau.


Pourtant, il faut bien donner une sémantique à
struct {
char tab[7];
double d;
} x , y= { "toto", 0.O } ;
x= y;

Je suis pas expert en recherche dans la norme, mais 6.5.16.1/1 définit
bien l'affectation comme le remplacement de 'value'. Donc, il faut
définir 'value' pour x et y. Et je ne vois pas comment faire sans
parler de 'value' pour tab.

Pour la norme C :

- Pour les lvalue qui ne sont pas de type tableau, on a une « valeur
contenue », synonyme de « valeur ». Pour les lvalue de type tableau, on
a une autre conversion, et on s'abstient de parler de valeur.


Et comment on exprime l'affectation entre tableaux dans des structures ?


Tu as raison. Je ne sais pas.

Donc, si tu es d'accord, on a

- pour le C, une notion de « rvalue » synonyme de « valeur », une «
valeur » synonyme de « valeur contenue », et un contexte (implicite,
certes) de valeur pour un tableau. Conclusion : la rvalue d'un tableau
existe et est son contenu (avec sens).

- pour le C++, une notion de « rvalue » définie pour un tableau : c'est
un pointeur (ou appelle le comme tu veux) vers son premier élément.

Donc C et C++ ont des définitions différentes de rvalue pour les
tableaux. C'est triste.

Bon... Outre le fait que je me découpe les cheveux en quatre, suis-je en
train de raconter des conneries ?


--
"Yo!"
Martin Heidegger (trad. Terrence Malick)



Avatar
Harpo
Pierre Maurette wrote:


Question aux gurus: il me semble évident qu'à partir du moment où une
variable est déclarée, et durant toute sa vie, l'opérateur adresse
renverra toujours la même valeur. Vous confirmez ?


Je ne suis pas un guru et me mefie des assertions évidentes.
Cela dépend peut-être de ce que l'on appelle 'la vie d'une variable' et
de l'implémentation.

par exemple :
{
int a;
int b;
int c;

a = 1;
printf("&a=%pn", &a );
b = 2;
c = 3;
printf("&c=%pn", &c );
a = 4
printf("&a=%pn", &a );
printf("&b=%pn", &b );
}

Il n'est pas évident que les 2 'printf("&a=%pn", &a );' renvoient la
même valeur.
On peut remarquer qu'on n'a jamais besoin des 3 variables automatiques
en même temps, a n'ayant pas à garder de valeur entre le 1er printf et
son affectation suivante, le compilateur peut faire en sorte de n'avoir
que 2 variables en même temps pour minimiser la taille de la pile :
a est d'abord alloué.
b est alloué à la place de a
c est pushé sur b
a est alloué à la place de c

Si on définit la durée de vie d'une variable automatique comme étant la
durée de vie du bloc dans laquelle elle est définie, on ne pourrait pas
assurer que l'opérateur adresse renvoie la même valeur si elle n'est
pas déclarée 'volatile', et ton assertion évidente serait fausse.

--
http://patrick.davalan.free.fr/

Avatar
Harpo
Emmanuel Delahaye wrote:

int a;
int *p = NULL;

p = &a;


Mais &a n'est-il un pointeur ?


&a est-il modifiable ? Non. C'est donc une adresse, pas un pointeur.


Tu es cohérent.
Un pointeur serait donc un objet auquel on peut affecter une adresse ?
j'ai souvent tendance à abuser du langage et autres bonnes choses.

--
http://patrick.davalan.free.fr/



Avatar
Marc Boyer
Le 31-03-2006, Yoxoman a écrit :

Là, c'est moi qui ne comprend plus rien. Dans le premier cas, p pointe
vers un entier, non ? Tu as bien écrit "int* p", ou c'est mes yeux ? :)


Oui, mais l'entier et le tableau ont la même adresse.
C'est la notion de 'pointe sur' qui n'est pas claire.


Je comprends. Comme je l'ai dit, pour moi « pointeur » est un type. Donc
« p pointe vers un tableau » sous-entend « p est une expression de type
pointeur vers tableau ».


D'accord, mais c'est pour toi. Pour certains, si p est de type T*,
quand p pointe sur le premier element d'un tableau, ils disent aussi
qu'il pointe sur le tableau (ce qui est 'classique' quand on
manipule des tableaux comme paramètres).
Certain disent aussi qu'un pointeur qui pointe sur une structure
pointe aussi sur son premier champs, alors que les types sont
différents.


Et pour en revenir à la phrase originale, « la valeur d'un tableau est
un pointeur vers son premier élément » serait formellement « la rvalue
d'une expression de type tableau est une expression de type "pointeur
vers le type du premier élément du tableau", et qui représente l'adresse
(ou le pointeur) du premier élément du tableau ». Ca fait beaucoup de
raccourcis, certes. Mais la question principale des raccourcis
linguistiques n'est-elle pas de savoir si ceux-ci peuvent avoir un sens
erroné ? Et je ne vois pas trop comment on pourrait interpreter celui-là
différemment de sa version formelle.


Ben, cf la remarque faite plus tard sur ce qu'est la valeur d'un
tableau (discussion sur les effectations de tableaux contenus dans
des structures).

Dans le premier cas, *p est de type
int, dans l'autre, il est de type int[4].


Oui, modulo 64. Ce que je dis, c'est que *p a une *valeur* (rvalue) de
type pointeur vers int.


Bof... A ce rythme là, il a aussi une valeur de type char*
(modulo sizeof(int)).


Comprends pas.


Ce que je dis, c'est que si on confond pointeur sur int, pointeur sur
tableau de int, on peut aussi bien confondre pointeur sur int et
pointeur sur char. Car a ce rythme, unt int, ça n'est qu'un tableau
de sizeof(int) char...

*p est de type array-to-T.


typedef int Tab64[64];
Tab64 a;
int* pi= a;
Trab64* pt= &a;

pi est de type pointer-to-int
*pi est de type int
pt est de type pointer-to-array-to-T
*pt est de type array-to-T


Oui. Et ?


Dans certaines de tes phrases, je ne comprenais plus de quelle
version de p tu parlais, donc, j'ai viré p et utilisé pi et pt.

Ce dont je parlait ici, c'est des énoncés du type « Whenever we use the
name of an array as a value, that name represents a pointer to the
initial element of the array. » (Accelerated C++).


Sauf avec sizeof et &.


Non. Tout est dans le « as a value ».


En effet.

Pour moi, pointeur est un type. Ou plutôt un ensemble de types (pointeur
vers T). Je considère « un pointeur » comme synonyme de « une
expression de type pointeur ». Et une rvalue est une expression...


Faut faire attention avec ces raccourcis. Car alors 1 est un int,
et 0.0 un double.


Sans réserve, je dis oui. Même si toi ou ED n'êtes pas d'accord. « 1 est
un int » dans le sens « 1 est une expression (constante) de type int (ou
entier) ». Tout comme

double d; // d est un double
int* p; // p est un pointeur

et qu'une 306, c'est une Peugeot.


En fait, je fais moi aussi ce type de raccourcis au jour le jour,
quand le contexte est clair. Mais quand on commence à évoquer
les relation pointeurs-tableaux, je préfère revenir à un vocabulaire
moins ambigue.

Ce singulier-pluriel (*la* valeur ; *ses* cases) peut-il avoir un sens ?
Ou alors la valeur de l'ensemble de ses cases ? Mais je ne sais pas ce
que c'est.


La valeur de l'ensemble de ses cases ? Tu ne vois pas ce que c'est ?


Hmm. Si. Finalement. Comme quoi.


OK

La norme C ne parle pas de rvalue. En note de bas de la page 46, on peut
lire : « What is sometimes called ??rvalue?? is in this International
Standard described as the ??value of an expression??. ».
On lit également (§3.17/1): « value : precise meaning of the contents of
an object when interpreted as having a specific type. ». Mais la norme
du C ne définit pas la « valeur » d'un tableau.


Pourtant, il faut bien donner une sémantique à
struct {
char tab[7];
double d;
} x , y= { "toto", 0.O } ;
x= y;

Je suis pas expert en recherche dans la norme, mais 6.5.16.1/1 définit
bien l'affectation comme le remplacement de 'value'. Donc, il faut
définir 'value' pour x et y. Et je ne vois pas comment faire sans
parler de 'value' pour tab.

Pour la norme C :

- Pour les lvalue qui ne sont pas de type tableau, on a une « valeur
contenue », synonyme de « valeur ». Pour les lvalue de type tableau, on
a une autre conversion, et on s'abstient de parler de valeur.


Et comment on exprime l'affectation entre tableaux dans des structures ?


Tu as raison. Je ne sais pas.


Moi non plus.

Donc, si tu es d'accord, on a

- pour le C, une notion de « rvalue » synonyme de « valeur », une «
valeur » synonyme de « valeur contenue », et un contexte (implicite,
certes) de valeur pour un tableau. Conclusion : la rvalue d'un tableau
existe et est son contenu (avec sens).


Je ne sais pas ce que dit la norme. C'est difficile ce type d'analyse
car, perso, je trouve des bouts de reponses de ci de là, mais etre sur
qu'il n'y a pas de contradiction quelque part ailleurs... Dans ce cas,
tant que je n'ai pas vu les paragraphes qui énoncent la règle
de copie des tableaux dans les structures, je reste méfiant.

Mais, comme je comprends les choses, la rvalue d'un tableau, c'est
bien le tuple composé des valeurs de ses cases. Après, quand on a
une expression de type 'tableau de T', dans certains contextes, elle est
implicitement convertie en une expression de type 'pointeur vers T'
ayant pour rvalue l'adresse du premier élement.
Je suis assez sur de l'idée, mais peut-être que la norme dit
les choses autrement.

- pour le C++, une notion de « rvalue » définie pour un tableau : c'est
un pointeur (ou appelle le comme tu veux) vers son premier élément.


Je suis trop incompétent en C++ pour cela. Lance une discussion
sur fclc++ si tu veux sur le sujet.

Donc C et C++ ont des définitions différentes de rvalue pour les
tableaux. C'est triste.


Un cros-post ?

Bon... Outre le fait que je me découpe les cheveux en quatre, suis-je en
train de raconter des conneries ?


Des conneries, je pense pas. Mais des erreurs, peut-être? je ne sais
pas.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)