C'est le type de la variable qui détermine le nombre d'octets utilisés, et non pas la valeur.
En l'occurrence tu as 2 int, peu importe les valeurs, ils occupent le même nombre d'octets en mémoire. Le standard C nous dit qu'un int fait au moins 2 octets, dans la pratique sur les plateformes récentes un int fait presque toujours 4 ou 8 octets.
Tu peux savoir ce qu'il en est sur ta machine en utilisant sizeof() qui prend en paramètre un type ou bien une valeur. Sizeof() te renvoie alors la taille du type en question,
printf("taille int = %zu\n", sizeof(int) );
// le format %zu car sizeof() renvoie un type size_t
Je veux comprendre si le compilateur fait une allocation de mémoire pour les constantes "12", "5", et "6" que j'ai utilisés dans mon programme.
Nop pas besoin, et le compilateur affecte 17 et 18 aux variables. Les 3 lignes ce-dessous sont parfaitement équivalentes, c'est le même code ASM qui sera généré par le compilo, avec les mêmes performances donc.
int a = 42;
int a = 30 + 12;
int a = 1 + 1 + 4 * 10;
les deux nombres '12' que tu as en lignes 5 et 6 n'occupent pas à proprement de la mémoire, avec le sens de «mémoire allouée». En fait, ils ne vont même pas «exister». Les compilateurs modernes en parsant ton code vont directement faire le calcul et affecter respectivement 17 et 18 aux deux variables nombre1 et nombre2.
Ensuite même les 17 et 18 ne vont pas forcément occuper de la mémoire conventionnelle. Ils seront effectivement présent dans le code (enfin si tu ne demandes pas au compilo d'optimiser), mais dans la mémoire utilisée pour stocker le code. Dans l'état le code produit assignera sans doute directement ces valeurs à des registres.
En résumé : tes '12+5' et '12+6' ne consomment rien.
Pour le reste l'explication donnée par Gam' est correcte.
Edit: grillé
Remarque : il faut toujours privilégier la lisibilité. Si, pour une raison ou une autre, dans un code '12+6' est plus lisible garde le.
Le titre est un élément important qui ne doit pas être négligé. N'oubliez pas cette règle simple : le titre idéal résume la question que vous allez poser en une petite phrase. Il doit permettre aux visiteurs de se repérer facilement dans le forum visité et d'identifier le sujet à sa seule lecture.
Vous pouvez utiliser divers préfixes comme [Erreur], [MySQL], [Compatibilité], etc... Aussi, pensez à consulter les règles propres à chaque forum (visibles dans les topics épinglés en haut des sections).
De plus, choisir un bon titre permet de rendre plus faciles les recherches des autres membres.
Les titres de type "besoin d'aide" ou "problème" ne sont pas tolérés.
Pour modifier votre titre, éditez le premier message de votre sujet.
Egalement, il faut savoir que le compilo est capable d'optimiser les ressources. Par exemple dans le cas de chaînes de caractères constantes, il va réduire à une seule ressource toutes les chaines identiques.
On voit que le compilo a trouvé que c'était la même chaine, et a donc fait pointer les pointeurs sur la même zone. Comme ça doit rester constant, c'est une bonne optimisation !
C'est aussi la qu'on voit une "faiblesse" du C, pour des raisons de rétrocompatibilité, tu peux faire :
C'est aussi la qu'on voit une "faiblesse" du C, pour des raisons de rétrocompatibilité, tu peux faire :
char* test = "toto";
Alors que la logique voudrait que ce soit :
const char* test = "toto";
Bin justement tant qu'on en parle, c'est là que ce n'est pas clair pour moi. Techniquement ta variable test n'est pas constante, on pourrait lui attribuer l'adresse d'une autre chaîne. C'est ce qui est pointé qui est constant dans ce cas, mais rien n'empêche plus loin de lui attribuer une table de char déclarée comme telle :
char* test = "toto"; -> pointe vers constante (R)
char myTab[25];
test = myTab; ->pointe vers variable (R/W)
Du coup un const type* toto désigne le contenu de toto comme constant où la zone pointée comme constante ? J'avoue ne pas beaucoup utiliser le mot clé const, mais probablement que je devrais, en théorie ça met à l'abri des effets de bords...
const char* test1 = "toto"; // test1 est mutable et pointe sur une chaine constante
et
char* const test2 = "toto"; // test2 est constante et pointe sur une chaine modifiable (toléré pour de sombres raisons historiques)
ni
const char* const test3 = "toto"; // test3 est constante et pointe sur une chaine constante
Donc test2 et test3 ne peuvent pas être réassignés, on ne peux pas modifier la chaine pointée par test1 ou test3. Et modifier la chaine pointée par test2 aura un comportement indéfini. Les 3 chaines "toto" peuvent être les mêmes ou pas.
int main()
{
int nombre1, nombre2;
nombre1 = 12+5;
nombre2 = 12+6;
return 0;
}
Le compilateur, pour peu qu'on lui demande gentiment (niveau d'optimisation), va voir qu'on ne fait strictement rien des variables nombre1 et nombre 2, et va donc se dispenser de réserver de la place en mémoire et d'y mettre quelque chose.
Déjà, sans optimisation, en mode con comme un balai, il peut fabriquer ceci
c'est à dire stocker les constantes dans la pile (et retourner à la maison en libérant la pile).
Bref, on ne peut pas trop prévoir ce que les variables du source C deviennent, une fois le programme compilé. Ce sont des abstractions.
Complément : souvent on croit savoir, et on se plante. Par exemple, soit une fonction qui échange deux cases d'un tableau, à partir de leurs indices. Le truc qui sert dans le tri.
On a tous appris un jour que pour échanger, on passait par une variable, etc.
void echanger1(int t[], int i, int j) {
int tmp = t[i];
t[i] = t[j];
t[j] = tmp;
}
parce qu'utiliser 2 variables pour l'échange, ça serait horriblement inefficace
void echanger2(int t[], int i, int j) {
int a = t[i];
int b = t[j];
t[i] = b;
t[j] = a;
}
Moralité : ne pas faire de "micro-optimisation" à la main dans du code C pour économiser une variable ou autre bricole: le compilateur fait ça tout seul très bien. En plus on risque d'écrire du code tordu dans lequel il ne pourra pas appliquer ses recettes d'optimisation, et celui qui devra remettre le nez dans le programme un certain temps après n'y comprendra rien.
Tu n'y comprendra rien si je n'utilise qu'une variable? Et que ferait le compilateur si j'introduit une macro du genre: #define echange(a,b) {int t=a; a=b; b=t;} et que je la place dans le code: echange(tableau[i], tableau[j]);
Le Tout est souvent plus grand que la somme de ses parties.
Pour un petit exemple comme l'échange de variables il n'y a pas de problème.
Les ennuis, c'est quand on se lance à faire le malin dans des trucs compliqués, en pensant "optimiser" parce que se base sur une idée fausse de ce que devrait faire le compilateur, et qu'on veut faire son boulot mieux que lui.
Le problème c'est que les cours de C poussent généralement dans ce (mauvais) sens, avec des questions comme "et si vous déclarez int z, la variable prend combien de place en mémoire" ?
La vraie réponse, c'est ça dépend. Ca va de zero à sizeof(int). Ca dépend de ce que le programme fait de la variable, ça dépend de ce que le compilateur va pouvoir simplifier.
PS: ta macro va avoir des problèmes avec les effets de bord, genre echanger(t[i++], t[j++]);
Pour les non avertis, voici ce que donne l'expansion de la macro: {int t=tab[i++]; tab[i++]=tab[j++]; tab[j++]=t;} En plus des indices qui ne sont pas corrects, ça ne ressemble en rien à un échange ...
- Edité par PierrotLeFou 27 août 2021 à 19:20:03
Le Tout est souvent plus grand que la somme de ses parties.
dans les boucles for, exemple for(int i=0; i<5; i++)
dans le swap
C'est pas étonnant que ça déconne.
Une version de swap par macro qui doit marcher correctement : on commence par récupérer les adresses dans des pointeurs, et ensuite on joue avec.
#define swap(a,b) { \
int *p = &(a), *q = &(b); \
int t = *p; \
*p = *q; \
*q = t; \
}
comme ça les paramètres effectifs de la macro ne sont utilisés qu'une fois.
Bon, ça marche
void test_incrementation(void) {
int t[10] = {12, 34}; // who cares ?
int i = 3, j = 5;
swap(t[i++], t[j++]);
assert(i == 4);
assert(j == 6);
}
Maintenant, question, est-ce qu'on gagne/perd entre
if (tab[j-1] > tab[j]) {
swap(tab[j-1], tab[j]);
}
et
if (tab[j-1] > tab[j]) {
int t = tab[j-1];
tab[j-1] = tab[j];
tab[j] = t;
}
Bon, suffit d'essayer : on compile avec les optimisations -gcc -O3 et on regarde le code généré : c'est le même. Le compilateur a éliminé le bricolage avec "address of" et les indirections.
(Bon quand même, le système de macros de C, ça fait quand même pitié, retrospectivement...)
Pas d'optimisation. Pour moi c'est juste plus clair. Je n'avais jamais pensé à mettre variables++ dans cette macro ...
Le Tout est souvent plus grand que la somme de ses parties.
Langage C
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Le Tout est souvent plus grand que la somme de ses parties.
Bonhomme !! | Jeu de plateforme : Prototype.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Bonhomme !! | Jeu de plateforme : Prototype.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
En recherche d'emploi.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.