Bonjour,
Est-il possible de savoir depuis le code du programme, s'il a été compilé en 32 ou 64 bits ?
Version imprimable
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 ?Citation:
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.Citation:
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:
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:
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 faisCode:printf("la taille d'un size_t est de %ld octets\n",sizeof(size_t));
, J'ai l'avertissement suivant :Code: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: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:
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: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 bitsCode:gcc -o ./a.out -pedantic -Wall -Wextra -march=i386 -m32
signifie une compilation pour l'architecture k8 (AMD64) avec un jeu d'instructions 64 bits.Code: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:
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:
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:
1
2
3 ARCH=LINUX gcc -Wall -W main.c -D$(ARCH) -o out
Grosse ânerie dectected.Citation:
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:printf ("%ld\n", (long) data);
Donc le cast n'est pas proscrit ?
Si on veut afficher un size_t en C90, je ne vois pas comment s'en passer.Citation:
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: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.Citation:
Envoyé par kromartien
char -> int
short -> int
int -> int
long -> long
float -> double
T * -> void *
quelles sont ces fonctions variadic pour la libc6 ?
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).Citation:
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.Citation:
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).Citation:
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é.Citation:
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.Citation:
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 :koi:
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. Alors :koi: Pas 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.
Je comprends ce que tu veux dire mais je trouve la formulation maladroite, les doubles ne fonctionnant generalement pas en decimal mais en binaire (de plus il y a une proposition pour ajouter des flottants decimaux qui s'appelleraient _Decimal*).Citation:
Envoyé par Emmanuel Delahaye
mais les nombres décimaux n'existent pas dans les ordinateurs. Ils ne sont que la traduction d'une représentation binaire. Le type double est juste très pratique pour représenter le résultat d'une division non-euclidienne 1/2 par exemple =0.5, ce qui ne correspond pas au type entier.Citation:
Envoyé par Jean-Marc.Bourguet
Et alors? Je ne comprends pas ton probleme.Citation:
Envoyé par kromartien
J'espere bien que si, sinon, a quoi ca servirait?Citation:
Mais modifier l'architecture cible de la compilation ne doit en rien modifier la sortie du compilateur
C'est certain.Citation:
Faire un source portable sur toutes les architectures demande en tout cas une bonne connaissance du C.
Mais si. Recherche BCD, Voir aussi http://www.open-std.org/jtc1/sc22/wg...docs/n1201.pdfCitation:
Envoyé par kromartien
(c'est pour un TR, pas une proposition pour inclusion dans la norme comme je le pensais; ca ne m'etonnerait pas que ca reviennent en proposition pour inclusion dans la norme puisqu'il y a l'air d'avoir une revision en projet).
J'ai corrigé...Citation:
Envoyé par Jean-Marc.Bourguet
Tu ne confonds pas avec les nombres réels à virgule fixes ?Citation:
Envoyé par Jean-Marc.Bourguet
quand je dis ne dois pas modifier la sortie du compilateur, je parle des messages d'erreur et des warnings. Le programme compilé va être différent c'est certain. À ce propos, j'ai pu remarquer que les programmes compilés pour AMD64 sont parfois plus volumineux que ceux compilés pour 386.
Ma difficulté, c'est de comprendre l'utilité d'un processeur 64 bits face au processeur 32 bits. Est ce que la seule différence entre les programmes se situe dans le codage des types définis par GCC définis pour chaque architecture, si oui comment le programmeur s'en sort-il et est-ce quil doit prévoir l'architecture de ses programmes en fonction de celle des processeurs, ou est ce que c'est le compilateur seul qui prend en compte les optimisations en fonction des jeux d'instructions machine de chacun des processeurs cible ?
Sauf que ce ne sont pas des réels non plus, car trop sont non-représentables. On pourrait parler de réels si on avait du calcul formel, mais il n'y a ici que des nombres à virgule, ou nombres non-entiers, etc. écrits généralements dans un format avec mantisse et exposant.Citation:
Envoyé par Emmanuel Delahaye
(l'expression "à virgule flottante", elle, je ne sais pas exactement ce qu'elle désigne).
Il y a plusieurs différences, notamment car le bus de données n'est pas le seul à passer à 64 bits: Le bus d'adresse aussi est agrandi, permettant le traitement de données plus volumineuses directement en mémoire.Citation:
Envoyé par kromartien
Ensuite, en effet le processeur peut mettre à disposition des instructions plus complexes, ou avoir la possibilité de faire deux opérations simultanément. Selon le type de processeur, cela peut être déterminé matériellement à l'exécution ou logiciellement à la compilation (la seconde solution permettant une meilleure optimisation car le compilateur peut mieux prévoir le futur que le matériel).
Avec du BCD on peut faire des virgules flottantes comme des virgules fixes.Citation:
Envoyé par Emmanuel Delahaye
n1201 concerne des nombres en virgules flottantes decimaux.
C'est ce que tu appelles mantisse et exposant. Mantisse dans ce contexte est impropre mais tres courant, quelque part entre la mode condamnee par l'academie et l'usage (*)Citation:
Envoyé par Médinoc
Il y a plusieurs formats pour representer des approximations de reels.
On parle de virgule fixe quand on les represente par un rationnel au denominateur fixe (les denominateurs populaires sont les puissances de 2 et de 10).
On peut reserver quelques bits pour indiquer le denominateur. Si le denominateur est represente par un nombre qui sert d'exposant a 2 ou a 10, on parle de virgule flottante.
Si on part du cote de la theorie de erreurs, la virgule fixe permet de representer les nombres avec une borne connue sur erreur absolue. Les representations en virgules flottantes permettent elle d'avoir une borne connue sur l'erreur relative. On aurait une meilleure borne sur celle-ci (pour un nombre fixe de bits dans la representation) en representant les nombres par leur logarithme (en virgule fixe), mais ca pose des problemes d'efficacites d'implementation. Pour des calcules sur des plages plus importantes, on a deja utilise le logarithme du logarithme.
(*)Quand une faute de français est commise par...
0,01 % des gens, c'est une coquille
0,10 % des gens, c'est une distraction
1,00 % des gens, c'est une faute
10,00 % des gens, c'est un barbarisme néologique
20,00 % des gens, c'est un googlisme peu recommandable
40,00 % des gens, c'est d'un registre relâché
60,00 % des gens, c'est une exception à la règle
80,00 % des gens, c'est une mode condamnée par l'Académie
100,00 % des gens, c'est l'usage
80,00 % des gens, c'est écrit dans le dico
60,00 % des gens, c'est un règle (avec des exceptions)
40,00 % des gens, c'est un ringardisme
20,00 % des gens, c'est recommandé par l'Académie
10,00 % des gens, c'est d'un charme vieillot
1,00 % des gens, c'est un archaïsme
0,10 % des gens, c'est un anachronisme
0,01 % des gens, c'est écrit dans le dico étymologique
-- Jean Fontaine