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

Identificateurs reserves de la bibliotheque standard

10 réponses
Avatar
candide
Bonjour,


Les normes C90 et C99 stipulent :


----------------------------- 8< ----------------------------------
7.1.3 Reserved identifiers
[...]
— All identifiers with external linkage in any of the following
subclauses (including the future library directions) are always reserved
for use as identifiers with external linkage.

— Each identifier with file scope listed in any of the following
subclauses (including the future library directions) is reserved for use
as a macro name and as an identifier with file scope in the same name
space if any of its associated headers is included.
----------------------------- >8 ----------------------------------


Dois-je comprendre (même si ce n'est pas dit formellement me
semble-t-il) que je suis autorisé à écrire un programme comme ceci :



------------- 8< ---------------
#include <stdio.h>

static size_t strlen(const char *s)
{
/* mon code de strlen */
}

int main(void)
{
printf("%u\n",strlen("toto"));

return 0;
}
------------- >8 ---------------

(ce qui paraîtrait logique) ?

10 réponses

Avatar
espie
In article <4870c685$0$15462$,
candide wrote:
Bonjour,


Les normes C90 et C99 stipulent :


----------------------------- 8< ----------------------------------
7.1.3 Reserved identifiers
[...]
— All identifiers with external linkage in any of the following
subclauses (including the future library directions) are always reserved
for use as identifiers with external linkage.

— Each identifier with file scope listed in any of the following
subclauses (including the future library directions) is reserved for use
as a macro name and as an identifier with file scope in the same name
space if any of its associated headers is included.
----------------------------- >8 ----------------------------------


Dois-je comprendre (même si ce n'est pas dit formellement me
semble-t-il) que je suis autorisé à écrire un programme comme ceci :



Non.

------------- 8< ---------------
#include <stdio.h>

static size_t strlen(const char *s)
{
/* mon code de strlen */
}

int main(void)
{
printf("%un",strlen("toto"));

return 0;
}
------------- >8 ---------------

(ce qui paraîtrait logique) ?



external linkage -> ca inclut toutes les fonctions, dont str*, et
quelques non-fonctions, comme errno.
Avatar
candide
Marc Espie a écrit :


external linkage -> ca inclut toutes les fonctions, dont str*,



Oui mais la norme précise :

"for use as identifiers with external linkage".

Ma fonction strlen est "static" donc mon identificateur est en liaison
interne et donc pas en liaison externe.
Avatar
Antoine Leca
En news:4870c685$0$15462$, candide va escriure:
Les normes C90 et C99 stipulent :
7.1.3 Reserved identifiers
[...]

Dois-je comprendre (même si ce n'est pas dit formellement me
semble-t-il) que je suis autorisé à écrire un programme comme ceci :
#include <stdio.h>
static size_t strlen(const char *s) { /* mon code de strlen */ }
int main(void) {
printf("%un",strlen("toto"));
return 0; }



Non, parce que size_t peut être incompatible avec unsigned (ce qu'un
compilateur moderne devrait t'avoir signalé).

Par ailleurs, l'utilisation de strlen est déconseillée (on préferera
strLen), mais reste conforme.


Antoine
Avatar
candide
Antoine Leca a écrit


printf("%un",strlen("toto"));







Non, parce que size_t peut être incompatible avec unsigned



Qu'aurais-je dû écrire ? ceci par exemple :

printf("%lun",(unsigned long)strlen("toto"));

?


>
> (ce qu'un
> compilateur moderne devrait t'avoir signalé).

gcc -W -Wall -pedantic reste silencieux.


Par ailleurs, l'utilisation de strlen est déconseillée (on préferera
strLen), mais reste conforme.



Merci de cette réponse.
Avatar
Eric Levenez
Le 15/07/08 02:54, dans <487bf562$0$12030$,
« candide » a écrit :

Antoine Leca a écrit


printf("%un",strlen("toto"));





Non, parce que size_t peut être incompatible avec unsigned



Qu'aurais-je dû écrire ? ceci par exemple :

printf("%lun",(unsigned long)strlen("toto"));



Je pense que c'est :

printf("%zdn", strlen("toto"));

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.
Avatar
Antoine Leca
En news:C4A21E4C.D27C4%, Eric Levenez va escriure:
Le 15/07/08 02:54, dans <487bf562$0$12030$,
« candide » a écrit :
Qu'aurais-je dû écrire ? ceci par exemple :

printf("%lun",(unsigned long)strlen("toto"));



printf("%zdn", strlen("toto"));



Les deux sont corrects. Le second nécessite que le printf() de la
bibliothèque standard implémente C99 (par exemple, cela risque de ne pas
être le cas avec Mingw, alors même que le compilateur utilisé clame être
conforme C99...)


On peut aussi écrire

printf("%un",(unsigned)strlen("toto"));

mais c'est considéré comme moins bon en règle générale (car certains
compilateurs permettent d'avoir des objets de taille supérieure à UINT_MAX,
64 Kio en 16 bits ou 4 Gio en 32 bits) ; la même raison fait préférer la
seconde version à la première, car il est même possible d'avoir des
implémentations (Win64 est la plus connue) où des objets peuvent avoir une
taille supérieure à ULONG_MAX...


Antoine
Avatar
candide
Antoine Leca a écrit :
Les deux sont corrects. Le second nécessite que le printf() de la
bibliothèque standard implémente C99 (par exemple, cela risque de ne pas
être le cas avec Mingw, alors même que le compilateur utilisé clame être
conforme C99...)



Je ne connais presque rien de spécifique à C99.

C90 est assez compliqué comme ça pour moi et me suffit.



On peut aussi écrire

printf("%un",(unsigned)strlen("toto"));




Je ne comprends pas ce que ça ajoute par rapport à

printf("%un",strlen("toto"));

puisque size_t est un type entier non signé.


mais c'est considéré comme moins bon en règle générale (car certains
compilateurs permettent d'avoir des objets de taille supérieure à UINT_MAX,
64 Kio en 16 bits ou 4 Gio en 32 bits) ;



strlen() retourne un entier de type size_t et ce type n'est-il pas
garanti pouvoir recevoir la taille du plus grand objet que
l'implémentation peut créer ?
Avatar
espie
In article <487cb490$0$6783$,
candide wrote:
Je ne comprends pas ce que ça ajoute par rapport à

printf("%un",strlen("toto"));

puisque size_t est un type entier non signé.



Et quelle taille ? printf est une fonction a nombre variable d'arguments,
de prototype
int printf(const char *, ...);

il n'y a donc pas de verif de type passe le format. Si tu es sur une plateforme
ou size_t vaut unsigned long, ton printf ne marchera pas: il recuperera juste
un unsigned int comme parametre.

Selon les cas:
- tu peux avoir de la chance, si ton size_t est inferieur a UINT_MAX, et que
les octets de tes valeurs sont dans le bon ordre, ca affichera la bonne valeur.
- tu peux avoir moins de chance, et recuperer un 0 correspond aux octets de
poids fort.
- pour un printf plus complique, avec d'autres parametres derriere, ca va
de toutes facons mettre la zone dans la lecture des parametres suivants.
- si tu n'as vraiment pas de bol et que tu es sur une archi exotique, ca
peut confuser ton programme, te faire lire une adresse de retour de travers,
avoir des effets de bords sur d'autres variables du programme, voire finir
en segfault.
Avatar
Antoine Leca
Tout-à-fait d'accord avec l'explication détaillée de Marc (que je ne vais
pas recopier), sauf pour un détail:

En news:g5ift4$1ckv$, Marc Espie va escriure:
printf("%un",(unsigned)strlen("toto"));


Je ne comprends pas ce que ça ajoute par rapport à
printf("%un",strlen("toto"));

puisque size_t est un type entier non signé.





<snip>
Si tu es sur une plateforme ou size_t vaut unsigned long,



... et que les long sur cette plateforme ont une taille ou une
représentation différente des int ...

ton printf ne marchera pas:
il recuperera juste un unsigned int comme parametre.


<etc., le reste inchangé>


Le détail est d'importance, car sur la plupart des machines de la période
1980-2010 (le règne des 32 bits), il n'y a _pas_ de différence entre int et
long.

Et la pinaillerie de rajouter le (unsigned) comme je l'ai fait plus tôt n'a
donc pas d'effet pratique sur « la plupart des machines ».

Le vrai souci, c'est que l'on voit bien, en particulier avec les machines à
architecture 64 bits, que l'on arrive au bout de cette période, ou du moins
qu'on commence à en voir le bout. Donc il devient urgent de bien prendre
conscience de ce « détail », et de prendre les « bonnes » habitudes, em
l'occurence comme explique Marc ne pas laisser un size_t comme argument
variable si la fonction attend un unsigned (ou vice-versa).


Si vous voulez un signe supplémentaire que l'on va au-devant de problèmes,
regardez l'attitude (opposée) qu'on pris les responsables des architectures
: sur Unix, ils ont décidé d'affronter le problème le plus tôt possible, et
donc ont forcé la conversion vers LP64, disociant int et long : donc
beaucoup de programmeurs doivent modifier le code (mal écrit) pour que cela
marche ; chez Microsoft --après avoir galèré trop longtemps avec les int
trop petits du temps de DOS et Windows 3.x-- ils ont choisi ce que l'on peut
appeler la politique de l'autruche, qui consiste à préserver le plus
longtemps possible le confort des tailles identiques, donc long reste sur 32
bits pour Win64...


Antoine
Avatar
-ed-
On 15 juil, 09:28, Eric Levenez wrote:

Je pense que c'est :

    printf("%zdn", strlen("toto"));




[C99] "%zu" pour un size_t...