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

prototype de la fonction main : pourquoi argc est il signé ?

22 réponses
Avatar
hibakusha
Bonjour à tous.

Pour le protoype suivant de main :

int main(int argc, char* argv[])

la norme indique pour argc :

"The value of argc shall be nonnegative."

L'utilisation de "shall" est perturbante, et je me demande ce qu'il
faut comprendre ici : est ce que cela veut bien dire que argc DOIT être
positif ? Et dans ce cas, pourquoi argc est il de type "int", c'est à
dire potentiellement négatif ?

Est ce moi qui comprends mal cette définition, ou bien y a t il la une
bizarerie, héritage quelconque d'un comportement etrange de certaines
version d'unix ou je ne sais quelle autre explication ?

Clairement, je me demande si il existe certaines situations où argc peut
être négatif ?

Et je me pose cette question avant de partir en vacances, c'est un signe...

Merci d'apporter vos lumieres sur le sujet...

(Je suis sûr que la question à déja été posée, mais je n'arrive pas a
mettre la main sur une réponse)

10 réponses

1 2 3
Avatar
Pascal Bourguignon
Vincent Lefevre <vincent+ writes:

Dans l'article ,
Pascal Bourguignon écrit:

Tout le monde est d'accord, ce serait mieux si c'était déclaré
unsigned int argc.


Non, je ne suis pas d'accord.

Mais le mélange de types entier N-bit non signés et de types entier
N-bit signés en complément à deux est toujours problématique, car les
intervales ne sont pas imbriqués, mais ont une intersection bizarre.


Voilà, les types non signés posent des problèmes et sont sources de
bugs (une valeur négative se retrouve facilement convertie en valeur
positive). De plus, ils ne permettent pas un contrôle d'overflow via
des traps (cf option -ftrapv de gcc).

Déclarer un type non signé juste parce qu'une valeur négative n'a pas
de sens, c'est idiot.


En C, oui. Mieux vaut mettre int partout, sauf dans le cas extrême
où on a besoin d'un bit de plus.

(Les langages qui ont un typage fort n'ont pas ces problèmes, et on
peut déclarer ou inférer des types non-signés sans difficulté. Mais ce
n'est pas le sujet).


En C, on le voit par les différent warnings qu'un compilateur donne,
et sur les erreurs invisible comises quand on mélange les deux.


Le compilateur ne donne pas toujours de warning. Le pire, c'est quand
ça marche en 32 bits, mais plus du tout en 64 bits, car les promotions
se font différemment (e.g. une promotion en un type signé devient une
promotion en un type non signé, d'où bug sur les valeurs négatives).


--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.


Avatar
Pascal Bourguignon
Erwan David writes:

Pascal Bourguignon écrivait :


En C, oui. Mieux vaut mettre int partout, sauf dans le cas extrême
où on a besoin d'un bit de plus.


Mouais, moi je dis qu'il vaut mieux voire au cas par cas...
ET quand on peut utiliser les types de taille fixe plutôt que int qui
va poser des problèmes de portabilité (ah les joies du int 16 bits quand
on porte un programme 32 bits...)


Il n'y a pas de type de taille fixe en C.

Sauf à considérer char, mais sizeof(char)==1 n'est que tautologique,
il faut voir limit.h et CHAR_BIT.

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.


Avatar
Pascal Bourguignon
Erwan David writes:

Pascal Bourguignon écrivait :

Erwan David writes:

Pascal Bourguignon écrivait :


En C, oui. Mieux vaut mettre int partout, sauf dans le cas extrême
où on a besoin d'un bit de plus.


Mouais, moi je dis qu'il vaut mieux voire au cas par cas...
ET quand on peut utiliser les types de taille fixe plutôt que int qui
va poser des problèmes de portabilité (ah les joies du int 16 bits quand
on porte un programme 32 bits...)


Il n'y a pas de type de taille fixe en C.


Si, en C99.

Sauf à considérer char, mais sizeof(char)==1 n'est que tautologique,
il faut voir limit.h et CHAR_BIT.


et uint32_t ?


Je n'ai pas le C99 lui-même, mais le final draft indique que ces types
de largeur exacte ne sont pas forcément présent (ce qui s'explique,
par exemple sur un processeur 36-bit).
http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/n843.ps.gz
section 7.18.1.1

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.




Avatar
Vincent Lefevre
Dans l'article ,
Pascal Bourguignon écrit:

Erwan David writes:
[...]

et uint32_t ?


Je n'ai pas le C99 lui-même, mais le final draft indique que ces types
de largeur exacte ne sont pas forcément présent (ce qui s'explique,
par exemple sur un processeur 36-bit).


Existe-t-il des plateformes supportant C99 mais pas ces types?

Je suppose que leur absence risque de poser des problèmes de
portabilité, notamment pour les formats qui utilisent des mots
de 16 et 32 bits (le problème d'endianness est réglé par les
fonctions htonl, htons, ntohl et ntohs, que l'on peut facilement
réimplémenter sur les plateformes qui ne les ont pas). Bien sûr,
on peut se débrouiller avec des types uint_leastN_t et des
masques, mais ce genre de chose devrait être le travail du
compilateur, pas celui du programmeur.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Pascal Bourguignon
Vincent Lefevre <vincent+ writes:

Dans l'article ,
Pascal Bourguignon écrit:

Erwan David writes:
[...]

et uint32_t ?


Je n'ai pas le C99 lui-même, mais le final draft indique que ces types
de largeur exacte ne sont pas forcément présent (ce qui s'explique,
par exemple sur un processeur 36-bit).


Existe-t-il des plateformes supportant C99 mais pas ces types?

Je suppose que leur absence risque de poser des problèmes de
portabilité, notamment pour les formats qui utilisent des mots
de 16 et 32 bits (le problème d'endianness est réglé par les
fonctions htonl, htons, ntohl et ntohs, que l'on peut facilement
réimplémenter sur les plateformes qui ne les ont pas). Bien sûr,
on peut se débrouiller avec des types uint_leastN_t et des
masques, mais ce genre de chose devrait être le travail du
compilateur, pas celui du programmeur.


Je suis bien d'accord, c'est pourquoi je n'utilise pas C pour des
programmes normaux :-)

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.



Avatar
Antoine Leca
En news:,
Pascal Bourguignon va escriure:
Il n'y a pas de type de taille fixe en C.


Si, en C99.


Je n'ai pas le C99 lui-même, mais le final draft indique que ces types
de largeur exacte ne sont pas forcément présent (ce qui s'explique,
par exemple sur un processeur 36-bit).
http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/n843.ps.gz
section 7.18.1.1


La norme à jour est disponible sur le site officiel de WG14,
www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

L'alinéa 3, qui n'était pas présent dans le FDIS, est intéressant dans ce
contexte (historiquement, cet alinéa a été rajouté par des pinailleurs, pour
éviter les argucies d'autres pinailleurs comme quoi une implémentation
pouvait se permettre de ne pas définir ces types, alors même qu'il est
évident qu'une telle implémentation n'aurait aucun succès commercial, donc
ne représenterait aucun intérêt réel en dehors des pinaillages.)

Il reste qu'une implémentation sur 36 bits ne définira pas ces types.
Autrement dit, si tu utilises int32_t, ton programme va planter à la
compilation sur un symbole non défini.
Cela tombe bien, sur une machine 36 bits il n'y a pas de bonne manière de
manipuler une quantité sur 16 ou 32 bits (surtout non signée.) Le programme,
si les types sont utilisés à bon escient, est donc maximalement portable !


Antoine



Avatar
Vincent Lefevre
Dans l'article <fae21c$689$,
Antoine Leca écrit:

L'alinéa 3, qui n'était pas présent dans le FDIS, est intéressant
dans ce contexte (historiquement, cet alinéa a été rajouté par des
pinailleurs, pour éviter les argucies d'autres pinailleurs comme
quoi une implémentation pouvait se permettre de ne pas définir ces
types, alors même qu'il est évident qu'une telle implémentation
n'aurait aucun succès commercial, donc ne représenterait aucun
intérêt réel en dehors des pinaillages.)


De toute façon, certains ne se privent pas de ne pas respecter les
normes lorsque ça leur pose problème.

Il reste qu'une implémentation sur 36 bits ne définira pas ces types.


Elle pourrait les définir.

Autrement dit, si tu utilises int32_t, ton programme va planter à la
compilation sur un symbole non défini.
Cela tombe bien, sur une machine 36 bits il n'y a pas de bonne manière de
manipuler une quantité sur 16 ou 32 bits (surtout non signée.) Le programme,
si les types sont utilisés à bon escient, est donc maximalement portable !


Avec des masques, c'est faisable. Certains processeurs ne sont
pas capables de manipuler des mots sur 16 bits, et pourtant les
implémentations fournissent bien un short sur 16 bits parce que
c'est utile dans la pratique.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

Avatar
Antoine Leca
En news:20070821075409$, Vincent Lefevre va
escriure:
Dans l'article <fae21c$689$,
Antoine Leca écrit:

Il reste qu'une implémentation sur 36 bits ne définira pas ces types.


Elle pourrait les définir.


Pas d'accord. Sur une machine 36 bits, un tel type sera inefficace (masquage
etc.), donc il me paraît plus utile de ne PAS définir ces types, justement
pour éviter qu'un programme qui cherche à utiliser une fonctionnalité
supposément à des fins de performances (c'est ce pourquoi ces types ont été
ajoutés) ne se fourvoit.


Certains processeurs ne sont
pas capables de manipuler des mots sur 16 bits, et pourtant les
implémentations fournissent bien un short sur 16 bits parce que
c'est utile dans la pratique.


Je n'ai pas la réponse définitive, mais je me demande dans quelle mesure les
dites implémentations ont fait cela « parce que c'était utile dans la
pratique », ou bien si c'était sous la pression des utilisateurs [payants ou
internes] qui n'arrivaient pas à recompiler leurs programmes qui assumaient
de manière aveugle que short===int16_t (alias la dictature du Vax).
La même logique a servie récemment à Microsoft pour décider que
DWORD===long===int32_t, y compris avec Win64, ce qui laisse la plateforme
supposément phare sans un vrai type entier de la largeur naturelle de la
plateforme... (ou comment couler le langage C sur la dite plateforme ?)


Dans la pratique, les short ne me serv[ai]ent que pour porter des programmes
entre le monde 16 bits et le monde 32 bits, sans changer de plateforme (et
avec des assertions du genre int==={short|long}, et long===int32_t :-/).
Et c'était avant C99, car sinon j'aurais utiliser int16_t à la place !
Un autre cas, c'est pour implémenter UTF-16/UCS-2/IP/UDP/TCP sur de vieux
compilos, et là encore uint16_t aurait été largement préférable (cf.
hton[ls]() dans XNS5.2/SUS...)

L'autre cas d'utilisation des short (pour les tableaux où on veut économiser
la place, un peu la même problématique que pour float), le fait que ce soit
sur 16 bits est sans objet.

Dans les cas un poil moins spécifiques, je me retrouve à utiliser des
unsigned char et à dépouiller à la main les structures, pas de short en
vue...


Antoine


Avatar
Vincent Lefevre
Dans l'article <fae96t$vv8$,
Antoine Leca écrit:

En news:20070821075409$, Vincent Lefevre va
escriure:
Dans l'article <fae21c$689$,
Antoine Leca écrit:

Il reste qu'une implémentation sur 36 bits ne définira pas ces types.


Elle pourrait les définir.


Pas d'accord. Sur une machine 36 bits, un tel type sera inefficace
(masquage etc.),


Probablement moins inefficace que si le masquage est fait par
l'utilisateur.

donc il me paraît plus utile de ne PAS définir ces types, justement
pour éviter qu'un programme qui cherche à utiliser une
fonctionnalité supposément à des fins de performances (c'est ce
pourquoi ces types ont été ajoutés) ne se fourvoit.


Non, ce sont les (u)int_fastN_t qui ont été ajoutés pour la
performance. Si un programme utilise uintN_t, c'est parce qu'il
a besoin d'un type a taille fixe. Et justement, comme uint32_t
est défini sur la plupart des machines, on peut supposer que les
programmeurs préfèrent l'utiliser plutôt que uint_fast32_t avec
masquage.

Certains processeurs ne sont
pas capables de manipuler des mots sur 16 bits, et pourtant les
implémentations fournissent bien un short sur 16 bits parce que
c'est utile dans la pratique.


Je n'ai pas la réponse définitive, mais je me demande dans quelle
mesure les dites implémentations ont fait cela « parce que c'était
utile dans la pratique », ou bien si c'était sous la pression des
utilisateurs [payants ou internes] qui n'arrivaient pas à recompiler
leurs programmes qui assumaient de manière aveugle que
short===int16_t (alias la dictature du Vax).


Certaines bibliothèques supposent cela. Un des problèmes est que
certaines structures liées au système ont des données sur 16 bits,
et avant C99, short était plus ou moins de seul moyen pour cela.
Tu peux voir quelques messages de l'enfilade:

http://groups.google.com/group/comp.sys.acorn.programmer/browse_thread/thread/8a414806a172a80e/

La même logique a servie récemment à Microsoft pour décider que
DWORD===long===int32_t, y compris avec Win64, ce qui laisse la plateforme
supposément phare sans un vrai type entier de la largeur naturelle de la
plateforme... (ou comment couler le langage C sur la dite plateforme ?)


Et int_fast32_t?

Dans les cas un poil moins spécifiques, je me retrouve à utiliser des
unsigned char et à dépouiller à la main les structures, pas de short en
vue...


Oui, mais ce n'est pas très pratique et probablement inefficace. Et
peu de programmeurs font cela, d'où problème si tu veux porter des
logiciels.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)



Avatar
Antoine Leca
En news:20070821100412$, Vincent Lefevre va
escriure:
Dans l'article <fae96t$vv8$,
Antoine Leca écrit:
donc il me paraît plus utile de ne PAS définir ces types, justement
pour éviter qu'un programme qui cherche à utiliser une
fonctionnalité supposément à des fins de performances (c'est ce
pourquoi ces types ont été ajoutés) ne se fourvoit.


Non, ce sont les (u)int_fastN_t qui ont été ajoutés pour la
performance.


Mmmmh. En fait, et ÀMHA évidemment, [u]int_fastN_t ne sert à rien, entre
autre ou surtout parce que personne ne l'utilise !
Sans compter qu'il est très difficile de définir correctement (comment
quantifier l'impact de la limitation de taille du cache ou celui des
différents microcodes ? sur x86-32, suivant les algorithmes et les versions
des processeurs ciblés, pour int_fast16_t tu auras parfois 16 et parfois 32
bits...)

Historiquement, les actuels [u]int{machin}N_t correspondent à une vision du
système de types (celle de F.Farance) proche des types paramétrisables genre
Ada. Après, cette vision a été modifiée/pervertie, entre autre pour la faire
coller avec l'existant <inttypes.h> ; c'est à ce moment qu'entré la notion
de [u]int_fastN_t, provoquée par la notation [u]int_leastN_t (un truc zarbi
qui a remplacé l'initiale notation [u]intN_t, qui avait la même
signification incluant le « au moins » N bits, mais qui prêtait beaucoup
trop à confusion.)
Je ne crois pas que [u]int_fastN_t fut une bonne idée.


Un des problèmes est que
certaines structures liées au système ont des données sur 16 bits,
et avant C99, short était plus ou moins de seul moyen pour cela.


En fait, l'interface avec les données de taille fixée par l'extérieur est LA
grande raison des [u]intN_t ! Le reste n'est que broderie.

Sauf que dans la pratique, l'ordre des octets importe aussi ; et bien sûr le
fait que cette normalisation est arrivée bien trop tard.


Dans les cas un poil moins spécifiques, je me retrouve à utiliser des
unsigned char et à dépouiller à la main les structures, pas de short
en vue...


Oui, mais ce n'est pas très pratique et probablement inefficace.
Et peu de programmeurs font cela, d'où problème si tu veux porter
des logiciels.


Cf. l'enfilade sur la supposition que le type int doit être réservé à
l'intervalle [-32768, 32767].


Antoine


1 2 3