J'ai un souci avec les déclarations, au niveau des const. Quand je fais un const unsigned char* truc; quelle est la différence avec un unsigned char* truc; ? Dans les deux cas, j'arrive à faire un truc++; (*truc)++; Quand je fais un unsigned char* const truc; Je ne peux plus modifier le pointeur, mais toujours les éléments pointés. Comment faire pour définir : - un pointeur modifiables sur des données non modifiables ? - un pointeur non modifiables sur des données modifiables ? - un pointeur non modifiable sur des données non modifiables ? Mici "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
unsigned char* p = La variable p et son contenu peuvent être modifiés Edité par geogeo le 02-01-2010 à 22:42:31.const unsigned char* p = Le contenu pointé par la variable p ne peut être modifié. unsigned char* const p = La variable p ne peut être modifiée. Et suspense, const unsigned char* const p = La variable et son contenu pointé ne peuvent être modifiés. la Nature nous montre seulement la queue du lion. Mais je suis certain que le lion a qui elle appartient pense qu'il ne peut pas se révéler en une fois en raison de son immense taille. - Fondateur de Ti-Gen -: http://www.tigen.org - Membre du Groupe Orage Studio -: http://oragestudio.free.fr/ - Mon site perso -: http://tisofts.free.fr Projets TI68K en cours: GFA-Basic = http://www.tigen.org/gfabasic Arkanoid. PolySn |
[22:31:15] <@Vertyos> (18:39:34) (Vertyos) const char* const maChaine = "kikoo"; Mea culpa, mes courtes vaccances m'ont fait oublier ce qu'on m'avait posté plus tôt. Qui plus est, certains de mes tests ont dû foirer du coup. J'ai cru comprendre qu'on ne recevait pas de warning si un test (genre *Ptr++) ne générait aucun code binaire "efficace" dans le programme, et donc le warning attendu ne se produit pas. Il faut alors faire un "return *Ptr++" pour être sûr que ce soit pris en compte (mais c'est chiant, faut modifier le proto dans le source et le header cross -> Merci quand même geogeo pour ton explication "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Non mais j'ai fumé aussi. Je viens d'édité mon post. la Nature nous montre seulement la queue du lion. Mais je suis certain que le lion a qui elle appartient pense qu'il ne peut pas se révéler en une fois en raison de son immense taille. - Fondateur de Ti-Gen -: http://www.tigen.org - Membre du Groupe Orage Studio -: http://oragestudio.free.fr/ - Mon site perso -: http://tisofts.free.fr Projets TI68K en cours: GFA-Basic = http://www.tigen.org/gfabasic Arkanoid. PolySn |
"const" est faible en C, dans le sens où un cast permet quand même de modifier une variable "const", si elle est stockée en RAM non protégée par une MMU: const int toto; *(int*)&toto = 1; // no problem, à moins qu'une MMU existe et protège en écriture la page contenant toto -> segmentation fault En C++, le compilo refuse de faire ça. Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
Je comprends mal pourquoi... Comment le compilateur pourrait-il interprêter autrement *(int*)&toto que en int toto ? Donc comment se fait-il berner si facilement ? Bon puis toute façon, j'aime pas trop l'idée de tricher de cette manière, j'essaye tant que possible de rester propre, et j'ai du mal, je débute. D'ailleurs un de ces 4, je vais poster mon code pour le soumettre à la critique et à l'audit populaire afin d'en retirer quelques fructueux conseils. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Folco (./5) :Il ne se fait pas berner, le langage C permet simplement de faire ce genre de choses, c'est tout. Ce n'est pas un langage qui force à être propre. |
Oui et puis c'est pas tricher, c'est juste forcer le compilateur à générer du code incorrect. Mais le compilateur s'en fout, il fait juste ce que tu lui demandes tant qu'il comprend ce que tu lui demandes. T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Lionel Debroux (./4) : Ha bon? Je vois pas de raison qu'il te refuse ça (et avec MSVC++ ça marche en tous cas). Mais de toute Folco c'est comme en assembleur, rien ne t'empêche de faire un truc du genre en pseudo-asm: .section text
pwet:
.long 0
$main
mov r0, :pwet
mov (r0), 1 "La vie est un grand terrain de jeu. On le sait quand on est enfant mais on l’oublie en grandissant." |
Normalement il est sensé refuser le cast de [truc] constant vers [truc] non constant. Tout au moins il doit émettre un warning si mes souvenirs sont bons. Mais de toutes façons (c'est plus visible en C++) le fait que tu réussisse à modifier la mémoire (en supposant que ce soit le cas) ne signifie pas que tu es arrivé à tes fins. Le const a une signification trop importante dans le code pour que ça soit aussi simple que ça. T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
g++ aussi (sans warning). Mais je ne suis pas un expert C++ (surtout que le const C++ ne veut pas dire la même chose que le const C). Et le code généré est à moitié correct. |
Ha ben j'ai même pas essayé de le lancer, c'est certain que ça va faire un segfault... [Edit] Ha ben non! const int i = 0; *(int*)&i = 1; std::cout << i << std::endl; Donne 0 en sortie... (en mode debug) En fait VC++ pousse directement 0 sur la pile puisqu'il prend ça pour une constante et crée un emplacement dans la section des variables pour référencer i, donc c'est un mauvais exemple. "La vie est un grand terrain de jeu. On le sait quand on est enfant mais on l’oublie en grandissant." |
Effectivement, pas de warning, mais: thunder:~ Fabien$ cat test.cpp && g++ -Wall test.cpp -o test && ./test
#include <iostream>
const int val = 1;
using namespace std;
int main(int argc, char *argv[])
{
const int *pValOk = &val;
int *pValNok = (int*)&val;
*pValNok = 2;
cout << "Val: " << val << endl << "Val 1: " << *pValOk << endl << "Val 2: " << *pValNok << endl;
return 0;
}
Bus error
(Mac OS X 10.5.8) EDIT: ./11 > Ouais c'est ce que je voulais dire par "signification trop importante" T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Pareil sous VC++ à ce moment. Ca n'a pas causé de problème avec mon exemple parce que les const int comme ça sont traités d'une façon plus proche du #define. C'est le genre de bidouille qui permet d'écrire: struct {
static const unsigned TAILLE = 32;
int truc[TAILLE];
}; "La vie est un grand terrain de jeu. On le sait quand on est enfant mais on l’oublie en grandissant." |
Vous voulez me mettre le pied à l'étrier pour lc C++ ou quoi ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Nan, je voulais juste compléter la sémantique de "const" par rapport à ./1 et ./2 (avec une information qui s'avère finalement fausse... il me semblait que les compilos courants étaient plus stricts que ça !) Comme GC le montre en ./12, il faut que la variable "const" soit globale pour qu'il puisse y avoir une protection de la MMU. C'était évident dans ma tête, mais j'aurais dû le marquer. Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
et que donne ça? (parce que la pile c'est tricher, les pages de pile sont à accès RW) GoldenCrystal (./12) : Nspire wiki CONDUCTEUR Va-et-vient Des QUATRE MANCHE AVEC DES DIODES |
La même chose Le truc important c'est que la variable soit globale (mais pas static ^^) pour pas qu'elle ne soit optimisée par le compilo. Pour le reste les deux autres auront le même comportement apparent en local ou global donc pas vraiment important. (Evidemment pour des raisons d'optimisation/performance/propreté c'est toujours mieux de mettre en local quand c'est possible) (Et bien sur pour la version où la variable est mise/optimisée en local, voir ./11) T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Quelqu'un pourrait poster un exemple de programme Windows qui plante à cause d'un accès en écriture à une variable const ? Je suis curieux de voir comment c'est implémenté dans l'exécutable. « Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau |
Ah oui, et si vous voulez pas que le compilo s'amuser à optimiser les accès aux variables, suffit de mettre volatile comme attribut. « Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau |
Normalement c'est tout bêtement fait avec les différentes sections de l'éxécutable. De mémoire pour les variables [globales] en lecture seule c'est .rdata . Et le volatile ça a quand même une signification un peu différente, c'est pas bien d'utiliser ça pour ça T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
j'aurais dit comme GC, les const en .rdata avec des pages read only. Nspire wiki CONDUCTEUR Va-et-vient Des QUATRE MANCHE AVEC DES DIODES |
C'est ce que je pensais, mais j'avais oublié l'existence des sections .rdata. Pour le volatile, c'est vrai que c'est pas explicitement le but de ce mot-clé, mais ça a l'effet secondaire désiré. ^^ « Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau |
Zerosquare (./18) : Je peux te donner des exemples en embarqué si tu veux La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork. |
Je parle du fait que ce soit protégé en écriture, pas du fait que ça plante « Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau |
Si c'est mappé en mémoire en lecture seule, hop ! La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork. |
C'est .rodata pour la lecture seule. |
pas sous windows Nspire wiki CONDUCTEUR Va-et-vient Des QUATRE MANCHE AVEC DES DIODES |
Bon, je reprends un vieux topic pour une simple question : C'est normal de devoir écrire des casts aussi brutaux ? if (!memcmp((void*)CustomType, (void*)&(((char*)FilePtr)[FileSize - 5]), 6)) FilePtr est un void*, qui me sert à calculer l'adresse d'un char (FileSize - 5), mais je dois passer à memcmp un pointeur sur un void, d'où le (void*)&. Ya pas moyen de faire plus lisible ? Plus intelligent ? Là ça me semble fouilli... Pourtant, en assembleur, ça serait tout con de calculer ce pointeur : movea.l FilePtr(pc),a0 move.w FileSize(pc),d0 lea -5(a0,d0.w),a0 Ca y est, je l'ai mon pointeur void avec ça... Ya pas plus clean et compréhensible à l'oeil ? ok, ça foirerait pour FileSize >= 2^15 mais là on s'en fout "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Ce n'est pas normal de devoir écrire ce genre de casts, c'est plutôt un indice que tu essaies d'écrire du C comme si c'était de l'assembleur. |