Bonjour,
Est-il possible de savoir depuis le code du programme, s'il a été compilé en 32 ou 64 bits ?
Bonjour,
Est-il possible de savoir depuis le code du programme, s'il a été compilé en 32 ou 64 bits ?
Peut être. A quoi ça pourrait bien servir ?Envoyé par oranoutan
Il a des morceaux de code dans le code principal que j'aimerai par exemple exécutés uniquement sur des environements 32 ou 64 bits ...
Du code 64 bit ne s'exécutera jamais sur une machine 32-bit. Ce genre de problème est réglé par la compilation conditionnelle. Il faut produire 2 exécutables (monappli32 et monappli64, à partir du même source) en changeant la définition des macros globales ad hoc.Envoyé par oranoutan
Ce sont les options du compilateur qui définissent l'architecture sur laquelle va être portée le programme, mais en compilant pour amd64, la valeur renvoyée par sizeof devient un long unsigned int.
La différence est dans l'adressage (8 octets au lieu de 4 octets) mais aussi dans la taille des différents types
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 TaillesEntiersAMD64.c : la taille d'un char est de 1 octets la taille d'un short est de 2 octets la taille d'un int est de 4 octets la taille d'un long int est de 8 octets la taille d'un long long int est de 8 octets la taille d'un float est de 4 octets la taille d'un double est de 8 octets la taille d'un long double est de 16 octets la taille d'un size_t est de 8 octets[EDIT](NB: je n'avais pas vu la réponse précédente. Est ce qui est entre [edit][/edit] correspond à ce que vous vouliez dire?)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 TailleEntiersi386.c: la taille d'un char est de 1 octets la taille d'un short est de 2 octets la taille d'un int est de 4 octets la taille d'un long int est de 4 octets la taille d'un long long int est de 8 octets la taille d'un float est de 4 octets la taille d'un double est de 8 octets la taille d'un long double est de 12 octets la taille d'un size_t est de 4 octets
Il y a un problème par exemple dans les lignes du genre. (je ne saurai pas étendre la démonstration, pas assez de connaissance du C) si je fais
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf("la taille d'un size_t est de %ld octets\n",sizeof(size_t));, J'ai l'avertissement suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part gcc -o ./a.out -pedantic -Wall -Wextra -march=k8 -mtune=i386 -m32 TailleEntiersAMD64.c. Est-ce qu'il faudrait remplacer le type du format de sortie par une macro pour avoir un code portable et maintenable autrement que par la fonction "remplacer" des éditeurs de texte ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part TailleEntiersAMD64.c:16: attention : format ‘%ld’ expects type ‘long int’, but argument 2 has type ‘unsigned int’
Je crois qu'il faudrai écrire le programme avec :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 #if ARCH == AMD64 #define SIZEOF_OUT "%ld" #elif ARCH == i386 #define SIZEOF_OUT "%d" #endif
pour éviter les erreurs de compilation et les warnings. Ça sûrement à voir avec le makefile et le ./configure, bien que je ne m'y connaisse pas trop.
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf("la taille d'un size_t est de SIZEOF_OUT octets\n",sizeof(size_t));
Ça donne sûrement une idée de ce qu'il ne faut pas faire pour écrire du code portable, mais c'est une question d'expert un peu. Je me demande par exemple si faire des casts est une bonne manière d'écrire un code portable.[/EDIT]
On remarque que les tailles des types "simples" (short, char, int, float, double) ne changent pas, seulement celles des pointeurs et des types strictement calculatoires du genre long long int et long double (long double sur 128 bits pour AMD64 donc deux registres du processeur, contre long double sur 96 bits pour i386, ce qui fait 3*32 bits=trois registres processeurs). Ça donne une certaine idée des optimisations de calcul possibles avec le processeur AMD64.
signifie une compilation pour le jeu d'instructions i386 avec des instructions 32 bits
Code : Sélectionner tout - Visualiser dans une fenêtre à part gcc -o ./a.out -pedantic -Wall -Wextra -march=i386 -m32signifie une compilation pour l'architecture k8 (AMD64) avec un jeu d'instructions 64 bits.
Code : Sélectionner tout - Visualiser dans une fenêtre à part gcc -o ./a.out -pedantic -Wall -Wextra -march=k8 -m64
Bonjour,
merci à vous deux pour vos réponses.
C'est quelque chose dans ce genre que je cherche mais je ne sais pas ou tu as trouvé le "ARCH", tu utilises quoi comme compilateur ? moi gcc.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 #if ARCH == AMD64 #define SIZEOF_OUT "%ld" #elif ARCH == i386 #define SIZEOF_OUT "%d" #endif
Je n'ai rien trouvé la dessus dans la doc.
Mais cela m'a donné une idée dont voici le code :
Si vous avez quelque chose de mieux n'hésitez pas, merci.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 char *arch; switch (sizeof(long int)) { default: arch="Inconnu"; break; case 4: arch="x86/32bits"; break; case 8: arch="x86-64/64bits"; break; } printf("architecture utilisée : %s", arch);
salut pour la compilation conditionnelle, utilise l'option -D de gcc
par exemple
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 ARCH=LINUX gcc -Wall -W main.c -D$(ARCH) -o out
Grosse ânerie dectected.Envoyé par oranoutan
Le format dépend du type, c'est tout.
Pour être tranquille, tu peux faire :
c'est portable et ça marche avec tous les types entiers signés de C90.
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf ("%ld\n", (long) data);
Si on veut afficher un size_t en C90, je ne vois pas comment s'en passer.Envoyé par kromartien
est la solution (note u et pas d, size_t est un type non signe). En C99 (et certains systemes le fournisse comme extension en C90), il y a "%zu" qui permet d'eviter le cast.
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf("%lu", (unsigned long) sizeof(int))
Il y a des cas où il est recommandé, voire obligatoire. C'est le cas des fonctions variadics, parce que la promotion (cast automatique) n'est pas forcément celle qu'on pense.Envoyé par kromartien
char -> int
short -> int
int -> int
long -> long
float -> double
T * -> void *
Les fonctions variadiques standards sont *printf et *scanf. Apres les systemes en ajoutent parfois (exemple: dans la famille des exec* sous unix, certaines sont variadiques).Envoyé par kromartien
Si la promotion automatique n'est pas celle que tu penses, il y a des risques que le cast n'aide pas parce que le resultat du cast va etre lui aussi promu.Envoyé par Emmanuel Delahaye
la promotion automatique c'est le fait que de arguments float soient transformées en double à l'appel d'une fonction par exemple ?
Oui, enfin promotion automatique, ça fait un peut redondant. 'promotion' suffit. (j'ai modifié mon post précédent).Envoyé par kromartien
dans quelle mesure alors faut-il utiliser les types double et int ? Est ce qu'il faut les privilégier à chaque fois, où pour les entiers par exemple, conaissant la gamme de variation, utiliser l'entier qui tient le moins de place ?
(un char quand c'est possible, pour i allant de 1à 10 par exemple on prend i comme char, sinon un short, sinon un int ou bien systématiquement des int , et des long int en cas de besoin avéré)
Pour ne revenir au sujet voici un bout d'un Makefile :
La partie en rouge précise l'architecture de compilation, par exemple la machine est un amd64 mais je "force" la compilation en 32bits pour la portabilité.CC = gcc
CFLAGS = -O3 -march=i686 -finline-functions -Wall
LDFLAGS = -s -lm ./shkComProcess.a
GCC = gcc -Wall -pedantic -g -O3 -unroll
etc....
D'ailleurs ca me vaut quelques soucis avec Valgrind qui est en 64bits et qui ne veut pas lancer cette appli....
Donc par le Makefile on peut le savoir, même chose en utilisant Valgrind & co, mais depuis le source d'un programme, pour ma part rien n'est spécifié et vu que je n'utilise pas de champs de bit, je ne m'en soucis pas.
Ce qui compte, ce n'est pas l'occupation mémoire, mais la simplicité. Les types char et short étant promus en int (même dans les expressions), il vaut mieux utiliser int directement, ça évite du code de promotion supplémentaire et inutile.Envoyé par kromartien
Si int ne suffit pas, on utilise plus grand. Si les valeurs réelles sont requises (résolution < 1 : résultat de division, par exemple) on utilise double. Si le plage est insuffisante, on utilise long double.
Les 2 types à privilégier sont donc :
- Entiers : int
- Réels : double
Ca couvre 90% des besoins.
Les types plus petits (signed char, short) sont utiles si on fait du stockage (gros tableaux). Jamais pour les paramètres, ni pour le calculs.
Oui mais l'architecture pour laquelle est compilée le programme n'est pas forcément la même pour chacun. Le programmeur ne va pas faire un source différent pour chaque architecture, c'est bien ça l'interêt d'avoir des sources.
La portabilité demande de prendre en compte beaucoup d'architecture pour lesquelles le langage C ne défini pas les types calculatoire long double et long int de la même manière.
le ./configure sert entre autre à déterminer l'architecture du processeur utilisé et à inscrire une variable ARCH dans le makefile je pense. Sous debian, la commande arch renvoie l'architecture du processeur.
Mais modifier l'architecture cible de la compilation ne doit en rien modifier la sortie du compilateur, et c'est toute la difficulté quand certaines fonctions ne renvoient pas le même type en fonction de l'architecture cible passée à GCC. Le plus sûr serait encore de mettre i386 pour tout le monde, mais les processeurs ont évolué depuis. Il faut également que les programmes marchent pour i386 aussi. Alors que faire ? mettre dans un source "Ce programme n'est pas exécutable sur i386" bien que gcc permette de le compiler pour i386![]()
Faire un source portable sur toutes les architectures demande en tout cas une bonne connaissance du C.
Le cast (étendre la valeur à un type plus large) est une solution, mais ce n'est pas non plus optimal. D'un autre côté, écrire les programmes en assembleur non plus. AlorsPas facile de savoir ce qu'il faut faire pour que le programme soit vraiment optimisé en fonction du processeur tout en gardant un source portable à l'extrême.
Partager