OVH Cloud OVH Cloud

[debutant] Que doit-on attendre de ce code ?

30 réponses
Avatar
bpascal123
Bonjour,
En apparence, ce code ne produit pas de r=E9sultat ni de message
d'erreur :

#include <stdio.h>

void print_vertical(char *str) ;

int main(int argc, char *argv[])
{
if (argc > 1)
print_vertical(argv[1]) ;

return 0 ;
}

void print_vertical(char *str)
{
while (*str)
printf("%c\n", *str++) ;
}

Merci

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Si j'ai bonne memoire, c'est d'ailleurs un petit point de difference
entre C et C++. Il me semble que la norme C++ donne un statut tres
particulier a main(), qui n'est vraiment pas une fonction comme les
autres, et qu'en particulier tu ne peux pas la rappeler de l'interieur de
ton programme...



Confirmé.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Antoine Leca
candide écrivit dans <news:4b13ef03$0$24788$:
J'ai pas vu un message précédent où tu fais un raisonnement relatif à
"la ligne de commande" (si tu pouvais citer le lien http de
groups.google plutôt que le liens <new&###!15744154584uiydgbciu...>
auquel je comprends rien ;) )



Recette à toute épreuve, partant par exemple de
<news:heok7j$fj7$
On lance son navigateur
Dans la barre d'adresses, on tape groups.google.com/groups?selm On découpe à la souris le message-id, heok7j$fj7$
On colle le message-id derrière le selm On tape entrée
On lit


Antoine
Avatar
Antoine Leca
candide écrivit :
Cela tient à mon avis au statut particulier de ces objets : ils
ne sont pas alloués par le programme mais par l'environnement.



Attention : ils ne sont pas alloués au sens de la norme.

Sinon, ce n'est pas vraiment l'environnement (qui n'est pas spécifié),
mais une partie de l'implémentation (nommée /program startup/ dans le
norme, et correspondant historiquement à une bonne part d'un fichier
objet passé à l'éditeur des liens en tout début de liste des arguments)

L'objet désigné par errno est dans la même catégorie.


En fait il y a 4 objets :
-- argc (fourni par l'environnement)
-- la copie de argc passé en argument à main() (les arguments sont
passés par valeur),
-- argv
-- les chaînes pointées dans le "tableau" argv .



Si on accepte que le « argv » dans ton énumération ci-dessus désigne le
paramètre (un pointeur vers tableau de chaînes) passé en argument à
main(), par le même mécanisme que pour « la copie de argc », il te
manque le "tableau" lui-même (construit à partir de l'environnement).


J'aurais tendance à dire que argc et argv sont de classe automatique et



Voui. Mais je ne veux pas parler de ceux-là (d'où mon appréciation
qu'Emmanuel a utilisé une mauvaise formulation au départ).

seules les chaînes pointées sont de classe statique.



C'est là où je ne suis pas d'accord. Pour moi le premier terme ci-dessus
ainsi que le tableau (le 5e article) sont aussi de classe statique.

Je lis 5.1.2.2.1§2 dernier alinéa comme

Mais la Norme ne dit rien.



??? Au seul endroit où elle mentionne les chaînes, elle mentionne les
deux autres objets...

Pourtant, dans un autre cas similaire où le programme alloue
un objet sans le déclarer, celui des chaînes littérales, la Norme prend
bien soin de préciser que les chaînes sont de classe statique.



Bzzz. « prend bien soin » est une lecture erronée de la norme.
Cette norme est en construction permanente : si des demandes
d'interprétation ou des rapports de défaut sont jugés suffisament
sérieux pour amener à de possibles malentendus sur la signification, le
comité rajoute du texte pour rendre le sujet limpide. Il ne faut donc
RIEN dériver de l'absence de texte précis sur un point, mais bien au
contraire prendre une lecture globale et tenter d'interpréter les
différents éléments. Si une seule explicaition est possible (et si elle
concorde avec la pratique), c'est la bonne ; si tu arrives à plusieurs
explications possibles (par exemple, s'il est possible de mettre les
littéraux chaînes sur la pile), il faut demander une interprétation car
il y a probablement un défaut ; et si tru arrives à une seule
explication MAIS que la pratique diffère, là tu es sûr qu'il y a un
défaut (ou cas plus probable à l'heure actuelle, tu t'es trompé quelque
part).


Par ailleurs, il y a une autre difficulté : la Norme ne donne pas
précisément la définition de la "classe" static, ni d'"automatic" ni
même d'"allocated" (rien de formel en tous cas). Elle dit d'abord qu'il
existe trois types de durée de mémorisation.



Il faut surtout comprendre que c'est une partition. C'est très évident
si tu remarques qu'au départ, la norme C89 ne mentionnait que les deux
premières, et que la troisième fut rajoutée suite à un commentaire, car
les objets créés par malloc() ne collent pas à la classse statique en
terme, justement, de /durée/ de vie.


Mais à la limite, je ne vois pas où la Norme m'empêcherait de
considérer que les arguments du programme (les chaînes) sont de
classe automatique !!



Bien justement, parce que le fameux dernier alinéa de 5.1.2.2.1
explicite que les chaînes doivent être encore valides dans la "program
termination" (donc tu peux les utiliser dans une fonction atexit() après
avoir sauvegarder un pointeur vers un de ces chaînes dans une variable
globale).


Antoine
Avatar
candide
Antoine Leca a écrit :
candide écrivit :
Cela tient à mon avis au statut particulier de ces objets : ils
ne sont pas alloués par le programme mais par l'environnement.



Attention : ils ne sont pas alloués au sens de la norme.



J'ai employé ce terme en me croyant autorisé à le faire : la Norme ne
l'emploi pas dans un sens uniforme : au départ, c'est une des durées de
mémorisation ("allocated storage duration") mais par la suite le terme
s'applique aussi à des tableaux ou des structures, exemple :

As discussed in 6.2.5, a structure is a type consisting of a sequence of
members, whose storage is allocated in an ordered sequence




Sinon, ce n'est pas vraiment l'environnement (qui n'est pas spécifié),




OK (note que le titre de la Partie 6 est "Environnement").





En fait il y a 4 objets :
-- argc (fourni par l'environnement)
-- la copie de argc passé en argument à main() (les arguments sont
passés par valeur),
-- argv
-- les chaînes pointées dans le "tableau" argv .



Si on accepte que le « argv » dans ton énumération ci-dessus désigne le
paramètre (un pointeur vers tableau de chaînes) passé en argument à
main(), par le même mécanisme que pour « la copie de argc », il te
manque le "tableau" lui-même (construit à partir de l'environnement).




Oui


J'aurais tendance à dire que argc et argv sont de classe automatique et



Voui. Mais je ne veux pas parler de ceux-là (d'où mon appréciation
qu'Emmanuel a utilisé une mauvaise formulation au départ).

seules les chaînes pointées sont de classe statique.



C'est là où je ne suis pas d'accord. Pour moi le premier terme ci-dessus
ainsi que le tableau (le 5e article) sont aussi de classe statique.

Je lis 5.1.2.2.1§2 dernier alinéa comme

Mais la Norme ne dit rien.



??? Au seul endroit où elle mentionne les chaînes, elle mentionne les
deux autres objets...



Oui. Mais je ne vois pas ce que ça prouve. La Norme dit que

"Each parameter has automatic storage duration. "



Au passage je lis un peu plus loin :

"The layout of the storage for parameters is unspecified."

C'est pas contradictoire avec ce qui précède ?





Bzzz. « prend bien soin » est une lecture erronée de la norme.





Oui, mon « prend bien soin » était un peu tendancieux ;)





Mais à la limite, je ne vois pas où la Norme m'empêcherait de
considérer que les arguments du programme (les chaînes) sont de
classe automatique !!



Bien justement, parce que le fameux dernier alinéa de 5.1.2.2.1
explicite que les chaînes doivent être encore valides dans la "program
termination"



Je sais bien que ce que je vais dire peut paraître absurde mais si je me
fie juste au texte de la Norme qu'est-ce que ça contredit le fait de
supposer que les chaînes soient de classe automatique puisque lorsque
lorsque le bloc qui définit main(), mon programme se termine et donc mes
chaînes s'évanouissent ?
Avatar
Alexandre Bacquart
candide wrote:
Antoine Leca a écrit :
candide écrivit :
Mais à la limite, je ne vois pas où la Norme m'empêcherait de
considérer que les arguments du programme (les chaînes) sont de
classe automatique !!



Bien justement, parce que le fameux dernier alinéa de 5.1.2.2.1
explicite que les chaînes doivent être encore valides dans la "program
termination"



Je sais bien que ce que je vais dire peut paraître absurde mais si je me
fie juste au texte de la Norme qu'est-ce que ça contredit le fait de
supposer que les chaînes soient de classe automatique puisque lorsque
lorsque le bloc qui définit main(), mon programme se termine et donc mes
chaînes s'évanouissent ?



Non. Elle sont statiques, elles persistent au retour de main() car
main() n'est ni le début ni la fin du programme.

Je crois que plus concrètement, il y a un cas où ça changerait
quelque-chose pour le programmeur : atexit(). Si main() se termine par
return x (mais pas exit()), c'est l'environnement qui appellera exit(x)
APRES le retour de main() (5.1.2.2.3 n'explique pas ce mécanisme de
manière très claire, il part du principe que return x ou exit(x), c'est
kif-kif, mais voir plus bas). Au final, exit() est toujours appelé une
fois, que ce soit manuellement ou automatiquement, et lui-même appelle
tous les myExit() enregistrés avec atexit().

Ce qui veut dire que le programmeur peut reprendre le contrôle après le
retour de main() et avant le nettoyage complet (vidage et fermeture des
flux, qui justement peuvent encore être utiles pour signaler un éventuel
problème détecté à la sortie).

Si on considérait que les chaînes de argv étaient automatiques, elles
n'existeraient plus à la sortie de main() et un myExit() qui les lirait
serait largué. Ca peut paraître tiré par les cheveux, car a priori ça
n'est pas le meilleur endroit pour traiter des arguments, mais je ne
m'attendrais pas à ce qu'un objet dit statique ne soit plus disponible
dans myExit() de toutes façons.


Sinon, voir le rationale 7.20.4.3 :

...

Aside from calls explicitly coded by a programmer, exit is invoked on
return from main. Thus in at least this case, the body of exit cannot
assume the existence of any objects with automatic storage duration
except those declared in exit.

...

Ce qui n'est guère plus clair à première vue (je suis loin d'être un
spécialiste de la bible), mais je ne vois qu'un truc du genre
exit(main(...)) (je schématise hein) coté appelant pour expliquer le
fait que les automatiques seraient compromis dans les cas où exit()
n'est pas appelé explicitement par le programmeur.

Enfin, un snip de Dinkumware accessible en ligne, plus limpide sur une
implémentation possible de tout ce blabla (et qui correspond plutôt à
l'idée que je m'en faisais) :

=======================================================================
*If main returns to its caller, the target environment calls exit with
the value returned from main as the status argument to exit*. If the
return statement that the program executes has no expression, the status
argument is undefined. This is the case if the program executes the
implied return statement at the end of the function definition.

You can also call exit directly from any expression within the program.
In both cases, exit calls all functions registered with atexit in
reverse order of registry *and then begins program termination*.
At program termination, the target environment closes all open files,
removes any temporary files that you created by calling tmpfile, and
then returns control to the invoker, using the status argument value to
determine the termination status to report for the program.

=======================================================================
--
Alex
Avatar
Antoine Leca
Alexandre Bacquart écrivit :
mais je ne vois qu'un truc du genre
exit(main(...)) (je schématise hein)



Tu ne schématises rien du tout ! Si tu regardes le code de crt0.c (quand
il est écrit en C), tu as de grandes chances d'y lire

exit(main(_argc, _argv, _environ));

_argc et _argv sont les deux objets /statiques/ (les noms peuvent
varier, en particulier certains ont rajouté des soulignés en tête pour
faire plus «inaccessibles») dont nous parlons depuis le début.


Je sais bien qu'une (ou plusieurs) implémentation n'est pas une preuve
de la norme, mais cela montre que ta lecture est bonne.


Antoine
Avatar
Antoine Leca
candide écrivit :
Antoine Leca a écrit :
candide écrivit :
Cela tient à mon avis au statut particulier de ces objets : ils
ne sont pas alloués par le programme mais par l'environnement.


Attention : ils ne sont pas alloués au sens de la norme.



J'ai employé ce terme en me croyant autorisé à le faire



Je n'ai aucune prétention à te l'interdire. De fait, tu as raison de
préciser que "allocated" est un terme passablement surchargé dans le
texte de la norme.
Je cherchais seulement à attirer l'attention des lecteurs sur le fait
que la durée de stockage n'est pas "allocated".


Mais la Norme ne dit rien.


??? Au seul endroit où elle mentionne les chaînes, elle mentionne les
deux autres objets...



Oui. Mais je ne vois pas ce que ça prouve. La Norme dit que

"Each parameter has automatic storage duration. "

Au passage je lis un peu plus loin :

"The layout of the storage for parameters is unspecified."

C'est pas contradictoire avec ce qui précède ?



Non, à partir du moment où on comprend que argc et argv sont les
_paramètres_ (des objets automatiques) qui sont différents des
_arguments_ (qui n'ont pas de noms définis par la norme).

Tu as toi même établi une liste de 4 ou 5 objets qui montre cette
distinction.

Si tu relis le paragraphe sur les appels de fonction, tu verras que
l'association entre argument et paramètre (une assignation) se fait au
moment de l'appel, et par la suite chacun vit sa vie. De ce fait, en C
les paramètres ne sont pas const, et il y a pas mal de programmes qui
profitent de ce fait et (ab)usent de paramètre comme si c'était une
variable locale supplémentaire. Évidemment, l'argument, de son côté,
reste intact tel qu'il était au moment de l'appel.


Antoine
Avatar
candide
Continuons notre "chicken or egg discussion"




Antoine Leca a écrit :
candide écrivit :
Antoine Leca a écrit :
candide écrivit :







Oui. Mais je ne vois pas ce que ça prouve. La Norme dit que

"Each parameter has automatic storage duration. "

Au passage je lis un peu plus loin :

"The layout of the storage for parameters is unspecified."

C'est pas contradictoire avec ce qui précède ?



Non, à partir du moment où on comprend que argc et argv sont les
_paramètres_ (des objets automatiques) qui sont différents des
_arguments_ (qui n'ont pas de noms définis par la norme).




Il n'y a pas d'arguments car c'est ainsi que la Norme les définit :

argument actual argument actual parameter (deprecated) expression in the
comma-separated list bounded by the parentheses in a function call
expression, or a sequence of preprocessing tokens in the comma-separated
list bounded by the parentheses in a function-like macro invocation


Le problème est que dans le cas de la fonction main(), sauf appel
récursif direct ou indirect, il n'y a pas d'appel du genre

main(42, vers_mes_chaines)

comme pour une fonction "classique"

f(42)

La Norme ne dit pas que c'est comme si on faisait

main(42, vers_mes_chaines)

mais elle dit juste :


The intent is to supply to the program information determined prior to
program startup from elsewhere in the hosted environment.

("The intent", bof, pas très précis)




Si tu relis le paragraphe sur les appels de fonction, tu verras que
l'association entre argument et paramètre (une assignation) se fait au
moment de l'appel, et par la suite chacun vit sa vie.



Bien sûr, c'est le principe du passage par valeur (mais ici il n'y a pas
d'appel main(42, toto)). Ici justement, l'objet donné par
l'environnement vit sa vie (et sa mort aux yeux du programme C puisqu'il
ne peut plus communiquer avec lui) et pour le programme C, seul existe
l'objet paramètre donné à main().




Pendant qu'on y est, puisqu'on a évoqué la question, comment
comprends-tu la phrase :


"The layout of the storage for parameters is unspecified."


"unspecified" c'est je suppose au sens de l'annexe J1. Mais qu'est-il
entendu par "layout". C'est quand même pas une histoire de "pile" ou de
"tas" puisque la Norme ne connait pas ces mots-là ? Ou alors ça veut
dire qu'on ne peut faire aucune supposition par exemple que les objets
seraient stockés avec des adresses qui seraient dans l'ordre
d'apparition dans la liste des déclarations des paramètres ?
Avatar
Antoine Leca
candide a écrit :
Le problème est que dans le cas de la fonction main(), sauf appel
récursif direct ou indirect, il n'y a pas d'appel du genre



Ma lecture des trois premiers mots du paragraphe 5.1.2.2.1 m'incite à
penser le contraire. Mais je n'arriverais pas à te convaincre, donc je
ne vais même pas essayer.


Pendant qu'on y est, puisqu'on a évoqué la question, comment
comprends-tu la phrase :

"The layout of the storage for parameters is unspecified."



Que la norme ne réglemente pas (au-delà des autres contraintes existant
par ailleurs) comment les paramètres sont organisés dans l'espace
d'adressage, ou dans des registres, s'ils sont alignés ou pas, se
recouvrent, etc.


"unspecified" c'est je suppose au sens de l'annexe J1.



Plutôt 3.4.4 ÀMHA.


Mais qu'est-il entendu par "layout".



« Disposition » ?

Cela devient peut-être plus clair si tu lis les propos du /Rationale/
(p. 96) à ce sujet : il y est expliqué en particulier que pour les
fonctions variadyques comme printf, la méthode utilisée par <varargs.h>
n'était pas suffisamment portable et devait être évitée dans des
programmes portables.


Antoine
Avatar
candide
Antoine Leca a écrit :
candide a écrit :
Le problème est que dans le cas de la fonction main(), sauf appel
récursif direct ou indirect, il n'y a pas d'appel du genre



Ma lecture des trois premiers mots du paragraphe 5.1.2.2.1 m'incite à
penser le contraire. Mais je n'arriverais pas à te convaincre, donc je
ne vais même pas essayer.




Le mot "function called" est employé certes mais pas au sens de
"function call" qui suppose un appel avec l'opérateur ().




Mais qu'est-il entendu par "layout".



« Disposition » ?



Oui, je connais le sens du mot layout mais dans ce contexte, ça ne me
semblait pas très précis ni très clair.


Cela devient peut-être plus clair si tu lis les propos du /Rationale/



Ah oui, j'avais pas pensé à regarder

(p. 96) à ce sujet : il y est expliqué en particulier que pour les
fonctions variadyques comme printf, la méthode utilisée par <varargs.h>
n'était pas suffisamment portable et devait être évitée dans des
programmes portables.



Ah OK, merci de ta réponse.
1 2 3