oki
Oui, bien sûr. Une structure doit avoir un alignement compatible avec tous ses éléments, elle a donc le plus grand alignement de ses éléments. Ainsi
Un tableau de A ou de B doit garantir que le champ x.b est toujours aligné 4 et que le champ x.a est aligné 2.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 struct A { short a; long b; char c; }; // => alignement 4 et taille 12 dont 5 octets de padding struct A2 { short a; int : 16; long b; char c; int : 24 }; // est équivalent struct B { long b; short a; char c; }; // organisation différente => alignement 4 et taille 8 dont 1 octets de padding
Il est recommandé de mettre les objets nécessitant un alignement important en première position.
Bonsoir,
Vous avez écrit, « Toutes les contraintes d’alignement/offset sont automatiquement prises en charge, c’est un avantage du C par rapport à l’assembleur. » D’accord, mais comment le langage C, peut-il, prendre en charge ces contraintes ?
Comment peut-il gérer les alignements ? Ce n’est pas le travail du compilateur ?
Peut-être que je me trompe (corrigez moi si c’est le cas), il me semble qu’il n’est pas d'avantage du langage C sur l’assembleur. Les compilateurs proposent des options, et des optimisations qui ont pour but d’améliorer les performances et d’ailleurs ce sont les compilateurs qui se chargent de faire tout le travail nécessaire pas le langage C.
« sizeof » ne gère aucun padding il permet de connaître la taille en octets de la structure en question et cette taille peut être supérieure à la taille des éléments, car « sizeof » tient compte de la représentation physique et intègre des zones inutilisées du cadrage sur un mot machine. Le padding vient du fait que le compilateur rajoute des octets pour respecter l’alignement et c’est là où il y a du gaspillage mémoire et que sizeof tient compte de ces octets padding, mais en aucun cas il les gère.
exemple:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 /* ============================================================================ Name : Untitled 4.c Author : SAMBIA39 Version : 0.1 Copyright : Copyright (c) 15/06/2016 SAMBIA39 Description : Ansi-style ============================================================================ */ #include <stdio.h> #include <stdlib.h> /* Les membres de la structures sont mal alignés un -Wpadded permet de nous le spécifié */ struct s_data_a{ char tab_A[3]; short data_s; /* defaut d'alignement le compilateur fait du padding */ char tab_b[1]; }; struct s_data_b{ char tab_b[1]; char tab_A[3]; short data_s; }; int main( void ){ struct s_data_a x; struct s_data_b y; fprintf( stdout, "size A\t:%ld\nsize B\t:%ld\n", sizeof(x), sizeof(y) ); return EXIT_SUCCESS; }
Le code que vous proposez en forçant l’alignement, me signale des erreurs d’alignement avec les options de compilation suivantes.
Code : Sélectionner tout - Visualiser dans une fenêtre à part gcc *.c -Wall -Wextra -Werror -Wpadded -o TEST
=> Entre deux éléments de mon tableau, il ne faut pas du padding ? comment le calculer/gérer ?:
Le padding influence sur la taille de la structure, il vous est possible de corriger ce gâchis manuellement soit en forçant l’alignement comme dans le dernier exemple de dalfab ou en faisant comme dans mon précédent exemple.
=> L'adresse du premier élément du tableau ne doit pas être aligné sur une adresse divisible par la taille de STRUCT_FOO ? Comment gérer ce problème ?: Quel est l’intérêt d’une telle manoeuvre ? Honnêtement, je n’ai pas vraiment saisi le fond de la question. Mais si vous souhaitez aligner ou gérer les alignements voire une zone mémoire correctement alignée vous avez les fonctions suivantes:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 void * aligned_alloc (size_t alignment , size_t size ); void * memalign (size_t boundary , size_t size ); int posix_memalign (void ** memptr , size_t alignment , size_t size );
à bientôt.
Celui qui peut, agit. Celui qui ne peut pas, enseigne.
Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
et les philosophes, qui ne connaissent rien sur tout.
George Bernard Shaw
Distinguer le compilateur de langage C du langage C, est d'une subtilité qui me dépasse.
Oui sizeof ne fait rien, mais sizeof d'un objet inclut toujours le padding éventuel qui devra être effectuéEnvoyé par sambia39
Avec les optionsEnvoyé par sambia39
-Wpadded
* Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure. Sometimes when this happens it is possible to rearrange the fields of the structure to reduce the padding and so make the structure smaller.
-Werror
* Make all warnings into errors.
On demande de considérer la nécessité de faire du padding comme un warning et on demande aux warnings d'être considérés en erreur
Vous avez écrit que «Oui sizeof ne fait rien, mais sizeof d'un objet inclut toujours le padding éventuel qui devra être effectué». D’accord, et j’ai écrit "sizeof tient compte de la représentation physique et intègre des zones inutilisées du cadrage sur un mot machine".
Zone inutilisée c’est le padding venant du fait que le compilateur rajoute des octets pour respecter l’alignement et honnêtement, je n’ai pas compris ce que vous avez essayé de me faire comprendre.
J’ai souligné que si je me trompais, que l’on me corrige.
De plus la phrase qui a été écrite peut porter à confusion. On peut comprendre que l’avantage du C par rapport à l’assembleur est que toutes les contraintes d’alignement/offset sont automatiquement prises en charge sans plus de précision à croire que c’est le C qui le prend en charge d’où peut-être l’intérêt d’un distinguo.
-Wpadded: Permet de savoir si une structure est alignée ou pas, et que si cela arrive, il est à la charge du développeur de faire le nécessaire pour réorganiser les champs afin de rendre la structure plus petite.
-Werror: Veut juste dire que tout warning est considéré comme erreur et de ce fait, la compilation est arrêtée donc:
veut dire:
Code : Sélectionner tout - Visualiser dans une fenêtre à part -Wall -Wextra -Werror -Wpadded -o TEST
Activer tous les warnings; activer les warnings de padding de structure; considérer tous les warning comme étant des erreurs ce qui arrête la compilation et affiche les erreurs.
voici un exemple en partant de mon code précédent:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 /* ============================================================================ Name : Untitled 6.c Author : SAMBIA39 Version : 0.1 Copyright : Copyright (c) 14/06/2016 SAMBIA39 Description : Ansi-style ============================================================================ */ #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> struct s_data_a{ char tab_A[3]; short data_s; char tab_b[1]; }; /*struct s_data_b{ char tab_b[1]; char tab_A[3]; short data_s; };*/ int main( void ){ struct s_data_a x; //struct s_data_b y; fprintf( stdout, "size A\t:%ld\n", sizeof(x) ); //fprintf( stdout, "size B\t:%ld\n", sizeof(y) ); return EXIT_SUCCESS; }
Code SORTIE COMPILATEUR : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 gcc source.c -Wall -Wextra -Werror -g -Wpadded -o OUT_TEST source.c:20:8: error: padding struct 'struct s_data_a' with 1 byte to align 'data_s' [-Werror,-Wpadded] short data_s; ^ source.c:18:8: error: padding size of 'struct s_data_a' with 1 byte to alignment boundary [-Werror,-Wpadded] struct s_data_a{ ^ 2 errors generated.
Le même code avec une autre variante de la structure
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 /* ============================================================================ Name : Untitled 6.c Author : SAMBIA39 Version : 0.1 Copyright : Copyright (c) 14/06/2016 SAMBIA39 Description : Ansi-style ============================================================================ */ #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> /*struct s_data_a{ char tab_A[3]; short data_s; char tab_b[1]; };*/ struct s_data_b{ char tab_b[1]; char tab_A[3]; short data_s; }; int main( void ){ //struct s_data_a x; struct s_data_b y; //fprintf( stdout, "size A\t:%ld\n", sizeof(x) ); fprintf( stdout, "size B\t:%ld\n", sizeof(y) ); return EXIT_SUCCESS; }
Code SORTIE COMPILATEUR : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5VMDesk:Desktop VMDesk$ gcc source.c -Wall -Wextra -Werror -g -Wpadded -o OUT_TEST VMDesk:Desktop VMDesk$ ./OUT_TEST size B :6 VMDesk:Desktop VMDesk$
Et les deux sans l'option "-Werror"
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 /* ============================================================================ Name : Untitled 6.c Author : SAMBIA39 Version : 0.1 Copyright : Copyright (c) 14/06/2016 SAMBIA39 Description : Ansi-style ============================================================================ */ #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> struct s_data_a{ char tab_A[3]; short data_s; char tab_b[1]; }; struct s_data_b{ char tab_b[1]; char tab_A[3]; short data_s; }; int main( void ){ struct s_data_a x; struct s_data_b y; fprintf( stdout, "size A\t:%ld\n", sizeof(x) ); fprintf( stdout, "size B\t:%ld\n", sizeof(y) ); return EXIT_SUCCESS; }
Code SORTIE COMPILATEUR : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 VMDesk:Desktop VMDesk$ gcc source.c -Wall -Wextra -g -Wpadded -o OUT_TEST_B source.c:19:8: warning: padding struct 'struct s_data_a' with 1 byte to align 'data_s' [-Wpadded] short data_s; ^ source.c:17:8: warning: padding size of 'struct s_data_a' with 1 byte to alignment boundary [-Wpadded] struct s_data_a{ ^ 2 warnings generated. VMDesk:Desktop VMDesk$ ./OUT_TEST_B size A :8 size B :6 VMDesk:Desktop VMDesk$
On remarque que l’on a deux structures identiques, mais l’un bouffe plus d’octets que l’autre j’espère qu’avec mes exemples vous avez compris.
à bientôt
Celui qui peut, agit. Celui qui ne peut pas, enseigne.
Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
et les philosophes, qui ne connaissent rien sur tout.
George Bernard Shaw
On cause justement d'allocation en bloc puisque ce sont des tableaux. Tu as beaucoup de tableaux de ce type à allouer et manipuler ? Sinon, économiser un appel sur deux via des interprétations d'adresses ô combien dangereuses c'est typiquement de l'optimisation prématurée, attention à ne pas tomber dans le you aren't gonna need it (je cause d'expérience ). Tu dis toi-même n'avoir rencontré aucun souci.
Si c'est le cas plus tard, il sera toujours temps pour toi de modifier le système. Tu peux utiliser un realloc, ou déclarer une partie du bloc en statique (si tu n'as jamais besoin de plus de N foos, autant déclarer foo tab[N];). Certes c'est moins flexible mais cette flexibilité (qui a un coût) est-elle pertinente pour ton projet ?
En effet le compilateur étant l'Implémentation du langage C (avec un grand I puisqu'on cause de la définition normalisée du langage), il ne m'a pas paru essentiel de faire la distinction théorique.
Faire le choix d'optimiser ou non un code c'est toujours la grande question mais s'il y a des méthodes simples pour le faire autant les utiliser. De manière général, j'essaie d'optimiser mon code lorsque que ça ne demande pas trop de temps supplémentaires en dev (temps de codage + temps de test).
Donc pour résumer :
- Si tableaux de dimensions fixes : utiliser une structure qui englobe tous les tableaux
- Si tableaux de dimensions non fixes : à traiter au cas pas cas (car risque d'erreur élevé. Et possibilité de ne pas détecter le problème => ex: on peut tomber sur le cas où l'alignement par chance est bon et lorsque le l'on recompile suite à un changement du code, que l'alignement n'est plus bon)
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager