Même sur PC, Kevin est pour l'optimisation taille. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Chose que je trouve assez absurde. Ce qui compte, c’est la taille de l’exécutable généré et la lisibilité du code. |
La taille de l'exécutable généré c'est complètement subjectif et dépendant de la problématique. Mais réduire la taille du code avant compilation c'est effectivement sans intérêt Y'a après une différence entre ce que fait Kevin, qui est compresser le code à outrance (au point même d'en perdre la vraie signification), et compresser plusieurs lignes en une seule. while (i != 0)
{
i = i - 1;
}Par exemple c'est complètement redondant. Le fait que le "= i - 1" puisse être optimisé en "-= 1" ou "--" est laissé au choix du codeur, de préférence sur des critères de lisibilité du code. Pour le reste, les { } sont par exemples inutiles (oui je les ai volontairement mis pour ça) donc ça va répartir le "code utile" inutilement sur 4 lignes au lieu de 2. Ensuite le (!= 0) est par définition du langage C fait implicitement (implicitement mais de manière explicite, vous suivez ? Ensuite, oui, le i-- (ou équivalent) peut carrément être mis à l'intérieur du while. while (i--) ;Est-ce vraiment moins clair ? Je trouve que ça a presque gagné en lisibilité moi. Sinon, pour l'utilisation des trucs réducteurs tels que ++ et += par exemple, ce que je fais par exemple: (Règle 1 pour tous les <opérateur>=; Règle 2 uniquement pour += et -= ) 1. Si c'est une opération "+ valeur" uniquement, réduire en "+=". Si c'est un "+ valeur1 + valeur2" alors non. 2. Si c'est réduit en "+=": Si c'est un "+ 1", et que ce n'est pas dans une série de "+=" (ou <opérateur>= quelconque), réduire en ++. Aussi, l'espacement du code est important. Pas à outrance, mais encadrer les opérateurs binaires par des espaces, et insérer des lignes vides entre des blocs d'instructions sans grand rapport. Donc entre les fonctions, mais aussi dans les fonctions ^^ Certains voudront même mettre plusieurs lignes vides, mais en général au delà de 2 c'est clairement abusif et ça diminue la lisibilité plus qu'autre chose. (deux c'est déjà limite...) T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Pour le "!= 0" c'est un sujet qui (comme beaucoup d'autres - Quand on compare une variable numérique (un compteur par exemple), le "!= 0" et le "== 0" ne devraient pas être retirés. Oui ils sont implicites, mais on veut comparer sa valeur, donc un nombre. À partir de là on écrit pas "if (count)" en se disant qu'on est un vraie génie à avoir économisé 4 caractères, mais "if (count != 0)" ou "if (count == 0)" en se disant que "vérifier si le nombre d'éléments dans mon tableau est vrai", ça n'aurait aucun sens. - À l'inverse, quand on compare une variable qui est utilisée comme booléen, il serait stupide d'écrire "== 0" ou "!= 0" : on ne veut pas la comparer à zéro, on veut savoir si elle vaut vrai ou faux. Donc "if (flag)" ou "if (!flag)". |
Hmm oui c'est vrai ( ./82 ^^) le cas de la boucle vide ça marche bien sans le != 0 parce que c'est une sémantique type booleen Dans le cas pratique c'est plutôt while (i-- > 0) faire_quelque_chose(i); T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Tiens, mon promier problème avec "static", que je ne connais pas. J'ai un Masked Big Sprite de Genlib, que j'initialise comme ça : MBGS Cursor =
{
16,
1,
{
0xFF
}
}; Le sprite est faux en dimension mais osef. Si je ne le déclare pas en static, j'ai l'erreur : error: non-static initialization of a flexible array member (near initialization for 'Cursor') Quand je rajoute "static" à la déclaration, ça marche sans problème. Mais pourquoi ? Qu'est-ce que ça change ? Qu'est-ce que ça signifie dans ce contexte ? Pourquoi il n'y en a pas besoin pour mes autres données ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Le type Cursor est de taille variable, donc ne peut pas être alloué sur la pile. |
Donc je suis obligé de lui dire moi-même qu'il ne va pas bouger ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Oui, et c'est à peu près ce que fait static. |
Bon, je suis toujours embêté avec les libs dynamiques et la compilation. Il y a des relogements, en soi pour le coup je m'en fous, mais tant qu'à faire j'aimerais bien les virer puisqu'il sont marqués comme "removables", et apparemment c'est pas fait. J'ai mis ça dans kernel.h : #define main _main #define _main __main #undef _main (made in PpHdland) Résultats des compilations : tigcc -v -Wall -W -O2 -mno-bss --optimise-code --cut-ranges --reorder-sections --remove-unused -ffunction-sections -fdata-sections [...] Program Statistics: Program Variable Name: main\asti68k Program Variable Size: 634 Bytes Absolute Relocs: 6 Natively Emitted Relocs: 0 Relocs Removable by Move Optimization: 10 Space Savable by Using GAS `-l' Switch: 20 Bytes Pour optimiser ça, puisqu'il dit pouvoir le faire, j'utilise -mpcrel : ====================================================================== *** Warnings *** asti68k.o: Warning: Library calls cannot be relative; changing to absolute. asti68k.o: Warning: Library calls cannot be relative; changing to absolute. asti68k.o: Warning: Library calls cannot be relative; changing to absolute. asti68k.o: Warning: Library calls cannot be relative; changing to absolute. asti68k.o: Warning: Library calls cannot be relative; changing to absolute. ====================================================================== *** Errors *** asti68k.o: Error: Cannot emit 2 byte library call to `butillib', function 0x0. asti68k.o: Error: Cannot emit 2 byte library call to `butillib', function 0x2. asti68k.o: Error: Cannot emit 2 byte library call to `butillib', function 0x3. asti68k.o: Error: Cannot emit 2 byte library call to `butillib', function 0x6. asti68k.o: Error: Cannot emit 2 byte library call to `butillib', function 0x1. /opt/gcc4ti/lib/tigcc.a: Error: Library calls are not supported in this mode. ====================================================================== Alors, ce que je comprends, c'est que je lui demande de tout faire en pc-relatif. Il me balance un warning pour me dire qu'il peut pas écrire les appels de dll en pc-rel, c'est évident, il passe en absolu, très bien. Mais alors pourquoi ces erreurs après ? Qu'et-ce qui lui va pas encore ? An'a marre ... "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
C'est --optimize-code, pas --optimise-code. Et tu ne peux pas utiliser -mpcrel avec des libcalls. Un libcall est forcément un relogement. |
Ok, je pensais qu'il savait se dire "je passe tout en pc-relatif sauf les libcalls, puisque évidemment c'est pas possible". Merci bien. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
J'ai ce code C : BufferSize1 = InitHandle(&Buffer1, BufferSize1, Name1); BufferSize2 = InitHandle(&Buffer2, BufferSize2, Name2); BufferSize3 = InitHandle(&Buffer3, BufferSize3, Name3); BufferSize4 = InitHandle(&Buffer4, BufferSize4, Name4); Qui donne ça : .LC1: .ascii "ab\0" .LC2: .ascii "cd\0" .LC3: .ascii "ef\0" .LC4: .ascii "ghijklm\0" .section .text._main,"x" .even .globl _main _main: link.w %fp,#-20 movm.l #0x1830,-(%sp) clr.b -1(%fp) pea .LC1 pea 10.w pea -4(%fp) lea InitHandle,%a2 jbsr (%a2) move.l %d0,%d4 pea .LC2 pea 10.w pea -6(%fp) jbsr (%a2) pea .LC3 pea 10.w pea -8(%fp) jbsr (%a2) lea (32,%sp),%sp move.l #.LC4,(%sp) pea 10.w pea -10(%fp) jbsr (%a2) Pourquoi ce move.l #.LC4,-(%sp) ? Pourquoi pas un pea comme les autres ? Il me fout un relogement pour ça, c'est nul comme comportement Et si je vire n'importe lequel de ces 4 appels de fonction, le relogement dégage... Comment forcer ça ?? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Attention, si tu regardes le code, tu verras qu'il n'y a pas de '-' devant "(%sp)", ce qui fait que cette instruction est différente d'un PEA. |
Oui je sais (je me suis planté au-dessus), mais le problème n'est pas là. Il fait ça pour ne pas avoir à dépiler 4 octets, je fais ça aussi en assembleur. Mais 4 octets de pile, j'en ai rien à battre, pourquoi fait-il ça ? Pourquoi un relogement ? On perd plus de place de binaire que 4 malheureux octets de pile dont on a rien à foutre "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Parce que l'optimisation sur le register transfer language (RTL) qui fait ça n'est pas au courant des détails du jeu d'instruction 68k, probablement. |
Et ya u moyen d'avoir un adressage relatif, même avec les appels de libs ? En sortant les appels de dll et en les mettant dans un autre fichier, puis en compilant séparément avec différentes options peut-être ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Et l'intérêt? Si tu as des appels de libs, tu as forcément des relogements, donc je ne vois pas pourquoi tu cherches à éviter les relogements internes à tout prix. |
Aucun intérêt c'est sûr. C'est juste que je voulais virer ce relogement que rien ne justifie techniquement. Edité par Folco le 11-02-2010 à 16:24:27."MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
J'attends ton correctif pour GCC. |
Tu sais très bien que je peux pas y arriver j'ai pas le niveau. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
awww pauvre folco Nspire wiki CONDUCTEUR Va-et-vient Des QUATRE MANCHE AVEC DES DIODES |
Autre question. Edité par Folco le 14-02-2010 à 15:51:28.Si j'écris : return a-- + 1; avec a type de base non pointeur (pour faire simple). Est-ce exécuté comme ça ? 1. on stocke ret = a + 1 2. on décrémente a 3. on retourne ret = a + 1 Ou comme ça ? 1. on calcule ret = a - 1 + 1 (vu que a-- + 1 == a) 2. on décrémente a 3. on retourne ret = a En fait, je ne sais pas ce que doit faire le langage : - évaluation de l'expression, décrémentation de a et retour de l'expression réévaluée après la décrémentation - évaluation de l'expression, retour de la valeur obtenue, et décrémentation de a juste avant le retour effectif Ca me parait ambigu, et je n'ai pas trouvé dans mon bouquin quel est le comportement attendu et garanti dans ce cas-là. edit -> rah je voulais parler d'un a-- et non d'un --a pour lequel c'est évident... "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Folco (./321) :Tes deux ret ont-ils la même valeur ? Sinon, pourquoi stocker une valeur inutile ? Dans la seconde proposition, pourquoi décrémenter a deux fois ? Tu peux simplement faire en premier les préincrémentations et prédécrémentations puis faire le calcul. Appliquer les postincrémentations et postdécrémentations et enfin retourner le résultat. |
La réponse à ta question est très simple Folco: Tu peux considérer que --a est équivalent à (a -= 1), autrement dit équivalent à (a = a - 1). (Idem pour ++a) C'est une pré-décrémentation (resp. pré-incrémentation) donc le comportement est simple, tu sais qu'elle a toujours lieu avant le reste des calculs, le reste n'a pas dimportance: L'ordre où le stockage "physique" des variables est effectué peut varier selon le compilateur et les optimisations, et n'a par conséquent aucune importance (ton --a pourrait même ne jamais avoir lieu), et sauf exception, ça n'influencera jamais le déroulement logique de ton programme. T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
C'est pas ça que je demande, j'ai dû mal m'exprimer. Je veux savoir le comportement d'un 'return a-- +1', quelque soit ce que je veux faire. CROSS ! Mon problème me semble évident avec un --a en effet, mais je pensais à a--, ce qui change tout (j'ai édité le post de ma question en remplaçant en conséquence). "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
return --a + 1; est équivalent à --a; return a + 1;. return a-- + 1; est équivalent à tmp = a + 1; --a; return tmp; ou à plus bas niveau %d0 = a + 1; --a; rts;. C'est la différence entre prédécrémentation et postdécrémentation. Maintenant, le compilateur n'est pas con, si a est local, il va optimiser ton return --a + 1; en return a;. |
./324 > Ah c'est malin Ben c'est un peu plus chiant car le post-incrément est effectué "après". Mais c'est globalement pareil. La norme te garantit que a++/a-- vaut a au moment de l'évaluation, et que a sera incrémenté/décrémenté après. (Je sais plus si "après" est directement après le ++/-- comme en C# ou à la fin de la ligne de code par contre, flemme de regarder, et de toutes façons il suffit de pas mettre deux ++/-- sur la même variable sur la même ligne Donc tu fais return a-- + 1; ça fait a + 1; ET a = a - 1; ET return "valeur"; Le reste est sans importance T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Ok ! Donc le '++' est exécuté après le calcul de toute l'expression. Dans mon programme, 'a-- + 1' est un peu plus complexe, il s'agit de ça en réalité : const char *GetNextArg(CMDLINE *Parser)
{
Parser->ArgIt++;
return Parser->ArgV[Parser->ArgIt - 1];
}Je me demandais si j'aurais pu écrire : return Parser->ArgV[(Parser->ArgIt)++]; Pour retourner Parser->ArgV[Parser->ArgIt], puis incrémenter Parser->ArgIt Ca fait bizare de se dire que les choses vont se passer comme si on effectuait une opération (en l'occurrence, l'incrémentation) après le retour. re-GC-cross : Voilà pourquoi j'ai écrit en deux lignes "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Oui ça peut te sembler un peu bizarre avec le coup du return, mais si tu réfléchis un peu, la ligne de code est éxécutée, le compilateur peut pas en zapper la moitié juste comme ça. Edité par GoldenCrystal le 14-02-2010 à 16:11:10.Donc ton ++/-- est forcément éxécuté quoi qu'il arrive (sauf bien entendu, si tu utilises des opérateurs de court-circuitage && ou || en même temps En fait le return est une opération en deux temps (dans le cas où il y a une valeur de retour), ① obtenir la valeur de retour ② quitter la fonction. Toutes tes opérations seront quoi qu'il arrive terminées avant le ② Après ce qui compte est le comportement "apparent" donc le compilateur peut optimiser ça comme il veut, changer l'ordre de tes opérations, l'ordre des lignes de code, supprimer des opérations, etc… Mais ça ne te regarde pas T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
(cross) ./327 : dans ton cas, l'écriture en une ligne est aussi correcte et plus claire je trouve (tu peux aussi virer les parenthèses) sinon non, le ++ est exécuté avant le calcul de l'expression, c'est juste que GC a présenté le déroulement déjà optimisé par le compilo sans optimisation, ça donne a1 = a; a = a + 1; ret = a1 + 1; return ret; et c'est ce comportement qui doit être conservé |