Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Warning sur l'évaluation d'une expression de type pointeur de fonction ("opera tion may be undefined")

23 réponses
Avatar
Xavier Roche
Bonsoir à tous,

Soit le petit programme suvant:

static void bar(void) {}
int main(void) {
void (*my_bar)(void);
(my_bar = bar, my_bar)();
return 0;
}

gcc me dit gentiment:
1.c:8: warning: operation on `my_bar' may be undefined

Question: en quoi la ligne "(my_bar = bar, my_bar)()" est-elle ambigüe ?
J'ai beau ouvrir grand mes yeux à cette heure tardive, je ne vois pas.

10 réponses

1 2 3
Avatar
Harpo
Xavier Roche wrote:

Bonsoir à tous,

Soit le petit programme suvant:

static void bar(void) {}
int main(void) {
void (*my_bar)(void);
(my_bar = bar, my_bar)();
return 0;
}

gcc me dit gentiment:
1.c:8: warning: operation on `my_bar' may be undefined

Question: en quoi la ligne "(my_bar = bar, my_bar)()" est-elle ambigüe
?
J'ai beau ouvrir grand mes yeux à cette heure tardive, je ne vois
pas.


J'utilise très peu l'opérateur ',' et je peux dire une connerie et je ne
vois pas très bien ce que tu veux faire.
Est-ce que tu veux faire :
my_bar = bar; my_bar();
Si c'est le cas, fais-le.

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

Avatar
Xavier Roche
Est-ce que tu veux faire :
my_bar = bar; my_bar();


Ma question portait surtout sur le *pourquoi* du warning (au passage, en
-Wall sur gcc), pas comment je pourrais faire autrement :p

[ Oui, dans cet exemple simple, on peut modifier le code évidemment.
Mais le vrai code est intégré dans une macro un poil plus complexe qui
est vue comme une fonction statique, donc, pour résumer, pas impossible
de s'en passer sans complexifier le code]

Avatar
Harpo
Xavier Roche wrote:

Est-ce que tu veux faire :
my_bar = bar; my_bar();


Ma question portait surtout sur le *pourquoi* du warning (au passage,
en -Wall sur gcc), pas comment je pourrais faire autrement :p

[ Oui, dans cet exemple simple, on peut modifier le code évidemment.
Mais le vrai code est intégré dans une macro un poil plus complexe qui
est vue comme une fonction statique, donc, pour résumer, pas
impossible de s'en passer sans complexifier le code]


Je pense que c'est parce que my_bar est à la fois left-value et
right-value et qu'il n'est pas initialisé avant l'affectation. Je ne
connais pas la macro mais en inversant bar et my-bar ça devrait
marcher.

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


Avatar
Harpo
Harpo wrote:

en inversant bar et my-bar ça devrait marcher.


Je pense que je viens de dire une connerie, il est temps que j'aille me
coucher.

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

Avatar
Jean-Claude Arbaut
Xavier Roche wrote:
Bonsoir à tous,

Soit le petit programme suvant:

static void bar(void) {}
int main(void) {
void (*my_bar)(void);
(my_bar = bar, my_bar)();
return 0;
}

gcc me dit gentiment:
1.c:8: warning: operation on `my_bar' may be undefined

Question: en quoi la ligne "(my_bar = bar, my_bar)()" est-elle ambigüe ?
J'ai beau ouvrir grand mes yeux à cette heure tardive, je ne vois pas.



Je crois que j'ai trouvé. Indice: gcc 3.4.4 ne bronche pas si
on écrit seulement (my_barºr)();
Donc, tu essaies d'appeler avec l'ancien my_bar qui n'est
pas encore initialisé.

Avatar
Xavier Roche
Donc, tu essaies d'appeler avec l'ancien my_bar qui n'est
pas encore initialisé.


Qui n'est /peut être/ ("MAY be undefined") pas encore initialisé.

Bon, apparamment POSIX/ANSI ne standardise pas non plus l'ordre
d'execution entre les "," et le compilateur peut évaluer la partie
droite avant d'executer la gauche, si j'ai bien tout pigé.

C'est donc le même problème qu'avec l'évaluation des arguments d'une
fonction (qui peut se faire dans un ordre totalement arbitraire), hélas.

Avatar
Xavier Roche
Bon, apparamment POSIX/ANSI ne standardise pas non plus l'ordre
d'execution entre les ","


Bon en fait ce n'est pas ça, l'opérateur "séquentiel" (le ",") est
bien.. séquentiel, donc pas de problème d'ordre. Je n'ai pas trouvé la
spec exacte, mais il semble bien qu'il n'y ait pas de problème avec
l'ordre d'évaluation. (1)

D'ailleurs, le code:
char foo[42] = "foo!";
char *bar;
*(bar = foo, bar) = 0;
ne pose pas de problème .

Et donc pas normal que l'exemple plus haut donne des boutons à gcc. Il y
aurait-il une subtilité lié au pointeur de fonction ?

(1)

"Comma expressions"
<http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/co.htm>

"Precedence and Order of Evaluation"
<http://msdn2.microsoft.com/en-us/library/2bxt6kc4.aspx>

Avatar
Pierre Maurette
Bon, apparamment POSIX/ANSI ne standardise pas non plus l'ordre d'execution
entre les ","


Bon en fait ce n'est pas ça, l'opérateur "séquentiel" (le ",") est bien..
séquentiel, donc pas de problème d'ordre. Je n'ai pas trouvé la spec exacte,
mais il semble bien qu'il n'y ait pas de problème avec l'ordre d'évaluation.
(1)

D'ailleurs, le code:
char foo[42] = "foo!";
char *bar;
*(bar = foo, bar) = 0;
ne pose pas de problème .

Et donc pas normal que l'exemple plus haut donne des boutons à gcc. Il y
aurait-il une subtilité lié au pointeur de fonction ?


Ça sent le bug, non ?
J'ai modifié avec bar() qui fait quelque chose, puis radicalement:
int main(void) {
void (*my_bar)(void);
void (*bar)(void) = 0;
(my_bar = bar, my_bar)();
return 0;
}
-> Warning


Mais:
int main(void) {
void (*my_bar)(void);
void (*bar)(void) = 0;
my_bar = bar;
my_bar();
return 0;
}
-> Pas de warning

int main(void) {
void (*my_bar)(void);
void (*bar)(void) = 0;
(my_bar = bar, my_bar());
return 0;
}
-> Pas de warning

La dernière est intéressante et fait si j'ai bien compris ce que vous
voulez. La différence entre les versions 1 et 3 pourrait laisser penser
que l'appel de la fonction /pourrait/ se faire avant l'évaluation du
bloc contenant l'opérateur comma. Ce que semble confirmer le suivant:
int main(void) {
void (*my_bar)(void);
void (*dummy)(void);
void (*bar)(void) = 0;
dummy = (my_bar = bar, my_bar);
dummy();
return 0;
}
-> Pas de warning

Effectivament, la lecture en diagonale (recherche du mot function) de
votre lien:
http://msdn2.microsoft.com/en-us/library/2bxt6kc4.aspx
ne parle que de la liste d'arguments, mais à aucun endroit ne précise
que le calcul d'un pointeur de fonction ne doit être mené avant
l'appel. Bon, c'est quand même un peu sodomite, tout ça ;-)

--
Pierre Maurette


Avatar
Xavier Roche
http://msdn2.microsoft.com/en-us/library/2bxt6kc4.aspx
ne parle que de la liste d'arguments, mais à aucun endroit ne précise
que le calcul d'un pointeur de fonction ne doit être mené avant l'appel.


Euh, c'est le *résultat* de la () qui est utilisé pour appeler la
fonction, donc c'est normal qu'il soit calculé avant, il n'y a pas
d'ambigüité ici.

Je ne comprend donc toujours pas le warning.

Bon, c'est quand même un peu sodomite, tout ça ;-)


Oui et non - cela peut aussi indiquer une initialisation qui peut
potentiellement ne pas se faire, et donc potentiellement un joli crash
sur un autre compilateur. Le tout est de comprendre où se situe le hic.

Encore une fois je comprend que dans cet exemple:
(arg1 = 42, function = my_function, function)(arg1);
on ait des problèmes (parce que ICI arg1 peut être placé sur la pile
avant le calcul du pointeur de fonction, c'est à dire avant l'évaluation
de la séquence ",")

Mais là, l'opérateur "," GARANTI que la partie gauche sera évaluée AVANT
la partie droite, renvoyée comme valeur (et avec le bon type)

Avatar
Pierre Maurette
http://msdn2.microsoft.com/en-us/library/2bxt6kc4.aspx
ne parle que de la liste d'arguments, mais à aucun endroit ne précise que
le calcul d'un pointeur de fonction ne doit être mené avant l'appel.


Euh, c'est le *résultat* de la () qui est utilisé pour appeler la fonction,
donc c'est normal qu'il soit calculé avant, il n'y a pas d'ambigüité ici.

Je ne comprend donc toujours pas le warning.


Moi non plus, mais je pense que c'est ce qu'interprête gcc. Je ne vois
pas d'autre explication. En fait, dans
(my_bar = bar, my_bar)();
il semble voir deux opérations, l'appel de la fonction my_bar() [et non
expressionAvecComma()] et l'expression expressionAvecComma. Il
considère que l'ordre de ces deux opérations n'est pas spécifié.
J'admets que c'est étrange, mais en faisant des essais c'est cette
logique qui semble être suivie. Vous n'avez pas de warning avec:
my_bar = bar, my_bar();
ou équivalents:
(my_bar = bar, my_bar());
(my_bar = bar), my_bar();
((my_bar = bar), my_bar());

En gros, il vous suffit de placer l'appel de fonction dans le terme de
droite de l'oérateur comma, et non uniquement le calcul du pointeur.
C'est peut-être simple à modifier dans vous macros ? Je pense que oui,
pour une bonne raison:
en écrivant
(my_bar = bar, my_bar());
vous ne faites que forcer à l'exact comportement que vous attendiez de:
(my_bar = bar, my_bar)();
c'est à dire:
my_bar = bar;
my_bar();
dans cet ordre.

Après, savoir si cette susceptibilité de gcc est normale ou de l'ordre
du bug dépasse mes capacités.

--
Pierre Maurette


1 2 3