Ce n'est pas tant une question de gout que de ce que tu as besoin de faire.Citation:
Envoyé par stephl
Version imprimable
Ce n'est pas tant une question de gout que de ce que tu as besoin de faire.Citation:
Envoyé par stephl
Je ne vois pas de cas où je serais obligé d'obtenir l'adresse d'un tableau.Citation:
Envoyé par Jean-Marc.Bourguet
Quand on parle de conversion (ici, implicite double -> int), c'est la valeur servant à initialiser le paramètre qui est convertie, pas la valeur de la variable originale...Citation:
Envoyé par stephl
J'ai donne un exemple plus haut dans cette discussion:Citation:
Envoyé par stephl
http://www.developpez.net/forums/sho...0&postcount=57
Naturellement, on peut aussi dupliquer le code.
Si tu veux, mais le warning est suffisant pour m'alerter d'un problème. Ici, c'est clairement une incompatibilité de type.Citation:
Envoyé par Jean-Marc.Bourguet
On peut, mais ça a une autre signification. Ca sert notamment à initialiser un pointeur sur tableau.Citation:
Envoyé par stephl
Si tu dois manipuler des tableaux taille fixe, ça évite un paramètre. Type tableau recommandé (j'ai montré un exemple).Citation:
Envoyé par stephl
J'avais bien vu votre exemple (fort intéressant), cependant, c'est un exemple d'utilisation. Rien ne m'oblige à utiliser f(), et personnellement, je n'aurais pas coder de cette manière. Ce que je veux dire, c'est que je ne vois pas de situation où utiliser & devant un tableau s'impose.Citation:
Envoyé par Jean-Marc.Bourguet
Si on connaît la taille des tableaux à l'avance et que la fonction de traitement est spécifique, je préfère considérer que la fonction a obtenu un pointeur et intégrer la taille du tableau dans la boucle.Citation:
Envoyé par Emmanuel Delahaye
Peux-tu expliciter ?? je ne suis pas là...Citation:
Envoyé par Jean-Marc.Bourguet
:cfou:
Je viens de tester avec Visual pour const, et j'ai ces deux prototypes qui compilent :Citation:
Envoyé par Emdel
Edit: Et seul le second accepte un tableau const.Code:
1
2 void AfficherTableau(int (* const pcTab)[10]); void AfficherTableau(int const (* const pcTab)[10]);
Ce doit être le même problème que pour les const char * const *
Et si tu décides de changer la taille de ton taibleau, et que plusieurs fonctions reçoivent un tel tableau en paramètre? Il y a un enjeu de maintenance évident là-derrière. Tu peux, comme l'a montré Emmanuel, utiliser un type tableauCitation:
Envoyé par stephl
et centraliser ainsi la définition de la taille de ton tableau. Un codage en dur rendrait la maintenance très fastidieuse.Code:typedef int int_a [10];
Thierry
Pas si on utilise un #define pour la taille du tableau.Citation:
Envoyé par mujigka
Tu as raison!Citation:
Envoyé par stephl
Après, je pense que c'est à chacun de voir ce qu'il préfère.Citation:
Envoyé par mujigka
En fait, ça permet de s'assurer statiquement qu'on passe bien un tableau de la bonne taille et non un pointeur avec la taille pas loin.
Mais ça montre sa vraie puissance avec le C++ (même si là, on passe plus souvent une référence qu'un tableau).
Attention, c'est du gros C++ qui tâche, alors âmes sensibles s'abstenir:
Et pour information, la version C++ de la macro ARRAYSIZE() de Microsoft repose sur ce principe (templates etc.) pour ne marcher que sur les tableaux (erreur de compilation si on lui passe un pointeur).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 //La fonction normale, comme on l'emploie en C : void EcrireDansTableau(int *tab, size_t n); //Ici, un template qui détermine statiquement la taille. //N est considéré comme une constante connue à la compilation. //La fonction appelle son amie en lui passant la taille. //Et comme elle sera sans doute inlinée par le compilo, aucun cout en performance. template< size_t N > void EcrireDansTableauPtr(int (*pTab)[N]) { EcrireDansTableau(*pTab, N); } //Et ici, une fonction équivalente avec le tableau passé par référence //(plutôt qu'un pointeur) et le même nom. //Cela évite d'avoir à employer une syntaxe différente. //Voir à ce sujet la fonction Microsoft strcat_s(). template< size_t N > void EcrireDansTableau(int (&tab)[N]) { EcrireDansTableau(tab, N); }
PS1 : Voici l'adresse de la doc de strcat_s() :
http://msdn2.microsoft.com/en-us/lib...x4(VS.80).aspx
PS2 : Ici, je ne me suis pas amusé avec les const, une chose compliquée à la fois s'il vous plait!
Merci Médinoc pour cet exemple d'application intéressant!Citation:
Envoyé par Médinoc
Thierry
Oui, c'est ce que j'ai mis, mais je passe l'adresse d'un tableau non const et gcc rale. Pour moi, c'est pas logique et je soupçonne un bug de gcc (ce cas étant quand même hyper rare, je ne serais pas étonné).Citation:
Envoyé par Médinoc
Il faut donc un paramètre supplémentaire (ou une sentinelle)...Citation:
Envoyé par stephl
BofCitation:
Envoyé par stephl
Il y a des utilisateurs vicieux...Code:
1
2 #undef N #define N 100
http://forum-images.hardware.fr/imag...so/roxelay.gifCitation:
Envoyé par Médinoc
Je suppose que vous voulez dire:Citation:
Envoyé par Emmanuel Delahaye
En effet, mais l'utilisateur étourdi (qui pourrait très bien être moi :( ) n'a qu'à faire attention. Le C laisse beaucoup de libertés au programmeur et suppose que ce dernier sait ce qu'il fait.Code:
1
2 #undef N #define N 100
Oui, déjà corrigé.Citation:
Envoyé par stephl
Dans une union, on ne peut acceder qu'au dernier membre ecrit, ici b. Donc lire a est normalement interdit mais il y a une exception: quand l'union est une union de struct qui commencent par les memes champs, on peut acceder aux champs communs.Citation:
Envoyé par souviron34
Modifions legerement le code pour voir facilement comment du code incorrect peut etre genere:
Prenons une architecture little endian avec un char non signe. Le compilateur peut decider que sizeof(struct a) va valoir 4 comme un int pour des raisons de perf. Il peut aussi decider de maintenir le padding a 0. De meme sizeof(struct b) va valoir 4 et il va y avoir un peu moins de padding.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 struct a { char c; }; struct b {char c; char d; }; union u { struct a a; struct b b }; int getCFromA(struct a) { return a.c; } int getCFromU(union u) { return u.a.c; } union uu; ... uu.b.c = 'a';
Lire a.c et le transformer en int consiste donc a ajouter des 0.
getCFromA peut considerer que le padding est toujours present et valant 0. Donc lire simplement l'int qui se trouve a l'addresse.
Dans getCFromU, le compilateur ne peut pas generer un code aussi simple et se fier au padding. Il doit lire le char tout seul et l'etendre avec des 0 pour masquer la valeur eventuelle de u.b.d.
D'abord une remarque ..
J'ai compilé ton code, Jean-Marc, sur mon Linux (redhat 7.3) (la fonction f) et voici ce que j'obtiens :
Pour rappel, la ligne 5 est la ligne de définition de p1 (compilé avec -Wall -pedantic)Code:
1
2
3
4
5 .//test1.c: In function `f': .//test1.c:5: warning: initialization from incompatible pointer type .//test1.c:6: warning: unused variable `p2' .//test1.c:5: warning: unused variable `p1'
Quant à l'autre problème, je comprend ce que tu veux dire, mais il me semblait que la définition même d'une union était que l'adresse physique de départ était la même. Et que, réservant la place la plus grande (en l'occurence ici pour la structure b), si le(s) premier(s) élément(s) a(ont) la même taille, quelque soit ce qu'il y a derrière, physiquement c'est écrit au même endroit...
Et que dans ce cas (et uniquement dans ce cas) accèder l'un ou l'autre est rigoureusement identique...
Les structures a et b commençant par les même champs, je ne comprends pas pourquoi getCFromA(uu.a) n'est pas conforme?Citation:
Envoyé par Jean-Marc.Bourguet
Thierry
Les deux structs peuvent avoir la meme taille a cause du padding. Le compilateur peut faire des suppositions sur le padding (par exemple qu'il est toujours a 0) dans getCFromA et s'arranger pour que toutes les modifications d'une struct a respectent ces hypotheses et donc generer du code commeCitation:
Envoyé par souviron34
en supposant une convention telle que les struct tenant dans un registre sont passees dans le registre P0 qui en sortie de fonction contient un resultat entier.Code:
1
2
3
4
5 getCFromA: ret getCFromU: and P0,P0,#0x000000FF ret
Je veux bien qu'elles puissent avoir la même taille, mais le début est forcément physiquement à la même adresse, non ??Citation:
Envoyé par Jean-Marc.Bourguet
Donc si j'écris un char et que les 2 structures commencent par un char, le char commence et se termine au même endroit dans les 2 structures, non ??
Oui. Mais quand on accede au char par un struct a, le compilateur peut faire ce qu'il veut sur le padding. Supposer qu'il est toujours mis a 0 par exemple. Ou supposer qu'il peut l'ecraser. Ces suppositions ne sont pas valides quand il fait acces a un struct b. Elles ne sont pas non plus valides quand il fait acces a un struct a qui se trouve dans une union contenant un struct b. (D'ou le masquage du dernier octet dans mon exemple).Citation:
Envoyé par souviron34
J'ai déjà lu quelqu'un gueuler sur ce sujet ici.Citation:
Envoyé par Emmanuel Delahaye
Essaie ceci:
Ceci marche sous Visual 2005 en C comme en C++, et il me semble avoir lu ici que ça ne marche pas en C sous gcc.Code:
1
2 char ** ppCh1 = NULL; char const * const * pcpcCh2 = ppCh1;
Ce qui est normal, gcc a raison. Les règles du C et du C++ sont différentes. En C, on ne peut ajouter const qu'au niveau le plus extérieur:Citation:
Envoyé par Médinoc
Et à regarder rapidement, c'est ce qui bloque Emmanuel aussi.Code:char* const* ppcCh3 = ppCh1;