Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

sizeof d'un tableau typedef-é

35 réponses
Avatar
Pierre Maurette
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;

je voulais avoir automatiquement le sizeof de ma donnée de type
pixel_word. Sur Google, j'ai dû mal chercher, je tombe uniquement sur
des trucs bateaux concernant les tableaux une fois passés à une
fonction.

Après avoir constaté qu'évidemment il me suffisait de créer un
pixel_word bidon là ou je voulais le sizeof, puis passé du bidon au
temporaire, j'ai de fil en aiguille trouvé ça à mettre dans le .h qui
fonctionne (gcc 3.4):

static const size_t MPI_MUL = sizeof(pixel_word){};
ou
#define MPI_MUL (sizeof(pixel_word){})

Est-ce la bonne pratique ?

Merci et bonne journée...

--
Pierre Maurette

10 réponses

1 2 3 4
Avatar
Marc Boyer
Le 08-06-2007, Pierre Maurette a écrit :
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;

je voulais avoir automatiquement le sizeof de ma donnée de type
pixel_word. Sur Google, j'ai dû mal chercher, je tombe uniquement sur
des trucs bateaux concernant les tableaux une fois passés à une
fonction.


C'est quoi 'automatiquement' ?

#include <stdio.h>
#include <assert.h>
#include <stdint.h>

int main(){
typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];
typedef pixelNG_word pixel_word;

printf("%zun", sizeof(pixel_word) );
assert( sizeof(pixel_word) == sizeof( uint8_t) );
}

Après avoir constaté qu'évidemment il me suffisait de créer un
pixel_word bidon là ou je voulais le sizeof, puis passé du bidon au
temporaire, j'ai de fil en aiguille trouvé ça à mettre dans le .h qui
fonctionne (gcc 3.4):

static const size_t MPI_MUL = sizeof(pixel_word){};
ou
#define MPI_MUL (sizeof(pixel_word){})

Est-ce la bonne pratique ?


Ben, pourquoi passer par un temporaire ?

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

Avatar
Pierre Maurette

[...]

Ben, pourquoi passer par un temporaire ?


Merci.
Je ne comprends pas, j'ai certainement fait une mauvaise manip une fois
et suis parti à la recherche de la solution à un problème inexistant.
Désolé d'avoir réveillé fr.comp.lang.c avec mes bêtises ;-)

--
Pierre Maurette

Avatar
Laurent Deniau
On 8 juin, 08:29, Pierre Maurette wrote:
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;


Un commentaire en passant, je trouve que c'est une tres mauvaise
pratique de faire un typedef d'un tableau, meme de taille fixe. La
semantique de passage par valeur "naturelle" devient une semantique
par reference sans prevenir. De plus tu ne pourra pas retourner des
variables de ce type. Pourquoi ne pas mettre les tableaux dans des
structures?

a+, ld.

Avatar
Pierre Maurette
On 8 juin, 08:29, Pierre Maurette wrote:
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;


Un commentaire en passant, je trouve que c'est une tres mauvaise
pratique de faire un typedef d'un tableau, meme de taille fixe. La
semantique de passage par valeur "naturelle" devient une semantique
par reference sans prevenir. De plus tu ne pourra pas retourner des
variables de ce type. Pourquoi ne pas mettre les tableaux dans des
structures?


Le contexte est assez particulier. Il s'agit de découper des données
entre des machines d'un cluster (la portabilité est donc encadrée par
MPI, par exemple mon boutisme est connu). Je n'ai pas droit au padding
(sauf celui interne prévu dans le pixelRGBA_word et qui n'en est pas
vraiment un).

J'avais dans un premier temps un:
typedef uint8_t pixel_word;

pour tester.

J'ai vérifié que tout fonctionnait avec un:
typedef uint32_t pixel_word;

J'aurais d'ailleurs pu en rester là (éclater le uint32_t), mais je ne
voulais pas de cast plein le code et voulais pouvoir tester des
uint24_t qui n'existent pas.

J'ai donc fait les trois typedef de tableaux, et le code a fonctionné
sans modification, pour la partie découpage, transport et parcours.
Pour l'instant, la partie calcul (j'ai ajouté des [0]) ne fonctionne
que sur l'élément 0. Mais tout se présente bien.

--
Pierre Maurette


Avatar
espie
In article ,
Laurent Deniau wrote:
On 8 juin, 08:29, Pierre Maurette wrote:
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;


Un commentaire en passant, je trouve que c'est une tres mauvaise
pratique de faire un typedef d'un tableau, meme de taille fixe. La
semantique de passage par valeur "naturelle" devient une semantique
par reference sans prevenir. De plus tu ne pourra pas retourner des
variables de ce type. Pourquoi ne pas mettre les tableaux dans des
structures?


Un commentaire sur le commentaire. Lorsque j'enseigne le C, je deconseille
toujours l'usage de typedef et l'usage de macros (*) aux debutants.

*: pour autre chose que de betes #define VALUE 42

En effet, d'experience, je ne les ai vu que faire des conneries avec ces
deux constructions. Ce sont des trucs vicieux qui ne sont guere utilisables
que par des bons.... Il y a meme des conneries dans C lui-meme, par exemple
(le top du top etant le FILE *, a mon avis, qui pue jusqu'au plafond et
au-dela).

Pour ma pomme, je n'utilise guere typedef que pour des equivalences entre
types numeriques. Jamais pour bidouiller sur des structures.

Les erreurs courantes de debutants sont de mettre des typedef sur des
struct ou des tableaux (oui, je n'aime pas). Entre:
typedef struct foo foo; // qui ne compile pas en C++
typedef struct foo *machin; // et hop, un pointeur tout ca.
typedef struct pouet pouet_t; // qui ne respecte pas la norme
on n'a que l'embarras du choix.

Sur les niveaux avances, c'est pas mieux: je ne compte plus les bibliotheques
qui ont des constructions bizantines de typedef... y compris dans leur API,
ce qui, bien evidemment, finit tres vite par poser des problemes de clash
de noms entre deux include de bibliotheques differentes qu'on voudrait
utiliser simultanement.

Il semblerait que le programmeur moyen ait beaucoup de mal a comprendre
a quel point un typedef est quelque chose de violent, puisque sa simple
presence suffit a rendre invalide tout le code C qui suit qui a le malheur
d'utiliser le nouveau nom de type pour n'importe quoi, y compris comme
nom de variable locale.


Avatar
Marc Boyer
Le 08-06-2007, Marc Espie a écrit :
Un commentaire sur le commentaire. Lorsque j'enseigne le C, je deconseille
toujours l'usage de typedef et l'usage de macros (*) aux debutants.

*: pour autre chose que de betes #define VALUE 42


Même un typedef sur des structs ?

En effet, d'experience, je ne les ai vu que faire des conneries avec ces
deux constructions. Ce sont des trucs vicieux qui ne sont guere utilisables
que par des bons.... Il y a meme des conneries dans C lui-meme, par exemple
(le top du top etant le FILE *, a mon avis, qui pue jusqu'au plafond et
au-dela).

Pour ma pomme, je n'utilise guere typedef que pour des equivalences entre
types numeriques. Jamais pour bidouiller sur des structures.


Qu'est-ce que tu appelles 'bidouiller' ?

Les erreurs courantes de debutants sont de mettre des typedef sur des
struct ou des tableaux (oui, je n'aime pas). Entre:
typedef struct foo foo; // qui ne compile pas en C++


Oui, mais c'est du C, non ?
D'ailleurs, mieu vaut empécher un débutant de compiler du
C avec un compilo C++, non ?

typedef struct foo *machin; // et hop, un pointeur tout ca.


Ben, oui, c'est écrit.

typedef struct pouet pouet_t; // qui ne respecte pas la norme


Idem avec les variables avec des _ mal placés...

on n'a que l'embarras du choix.

Sur les niveaux avances, c'est pas mieux: je ne compte plus les bibliotheques
qui ont des constructions bizantines de typedef... y compris dans leur API,
ce qui, bien evidemment, finit tres vite par poser des problemes de clash
de noms entre deux include de bibliotheques differentes qu'on voudrait
utiliser simultanement.

Il semblerait que le programmeur moyen ait beaucoup de mal a comprendre
a quel point un typedef est quelque chose de violent, puisque sa simple
presence suffit a rendre invalide tout le code C qui suit qui a le malheur
d'utiliser le nouveau nom de type pour n'importe quoi, y compris comme
nom de variable locale.


Bof. Que le C permette de faire des horreurs, ça ne me semble pas
une nouveauté. De là à interdire le struct...

Marc Boyer

Avatar
Pierre Maurette
In article ,
Laurent Deniau wrote:
On 8 juin, 08:29, Pierre Maurette wrote:
Bonjour,

A partir de ça:

typedef uint8_t pixelRGBA_word[4];
typedef uint8_t pixelRGB_word[3];
typedef uint8_t pixelNG_word[1];

typedef pixelNG_word pixel_word;


Un commentaire en passant, je trouve que c'est une tres mauvaise
pratique de faire un typedef d'un tableau, meme de taille fixe. La
semantique de passage par valeur "naturelle" devient une semantique
par reference sans prevenir. De plus tu ne pourra pas retourner des
variables de ce type. Pourquoi ne pas mettre les tableaux dans des
structures?


Un commentaire sur le commentaire. Lorsque j'enseigne le C, je deconseille
toujours l'usage de typedef et l'usage de macros (*) aux debutants.

*: pour autre chose que de betes #define VALUE 42

En effet, d'experience, je ne les ai vu que faire des conneries avec ces
deux constructions. Ce sont des trucs vicieux qui ne sont guere utilisables
que par des bons.... Il y a meme des conneries dans C lui-meme, par exemple
(le top du top etant le FILE *, a mon avis, qui pue jusqu'au plafond et
au-dela).

Pour ma pomme, je n'utilise guere typedef que pour des equivalences entre
types numeriques. Jamais pour bidouiller sur des structures.

Les erreurs courantes de debutants sont de mettre des typedef sur des
struct ou des tableaux (oui, je n'aime pas). Entre:
typedef struct foo foo; // qui ne compile pas en C++
typedef struct foo *machin; // et hop, un pointeur tout ca.
typedef struct pouet pouet_t; // qui ne respecte pas la norme
on n'a que l'embarras du choix.

Sur les niveaux avances, c'est pas mieux: je ne compte plus les bibliotheques
qui ont des constructions bizantines de typedef... y compris dans leur API,
ce qui, bien evidemment, finit tres vite par poser des problemes de clash
de noms entre deux include de bibliotheques differentes qu'on voudrait
utiliser simultanement.

Il semblerait que le programmeur moyen ait beaucoup de mal a comprendre
a quel point un typedef est quelque chose de violent, puisque sa simple
presence suffit a rendre invalide tout le code C qui suit qui a le malheur
d'utiliser le nouveau nom de type pour n'importe quoi, y compris comme
nom de variable locale.


En bref, il y les débutants et les bons.
Et le "programmeur moyen", qui a beaucoup de mal à comprendre et
surtout à comprendre qu'il ne devrait chercher à comprendre et qu'il
serait préférable qu'il ne programmât point.
Et puis il y a, non pas Frida, mais l'Enseignant, plus que bon et
n'ayant jamais débuté, bien que souvent n'ayant jamais quitté l'école.
L'Enseignant cultive au moins le paradoxe...
L'Enseignant préfère s'adresser à ses semblables et aux bons - et
encore... - qu'aux mauvais, aux moyens, et aux ... débutants ;-)

J'aurais aimé quelque chose d'utile, genre règle de nommage pour les
types typedef-és malgré l'opposition de l'Enseignant. C'est pourtant
ici que j'avais appris que le suffixage par _t était *très* mal. Je
m'étais rabattu sur le prefixage Petrus_, mais ça ne convient pas
toujours. Et j'aimerais bien un truc qui indique que c'est un type.

--
Pierre Maurette



Avatar
Marc Boyer
Le 08-06-2007, Pierre Maurette a écrit :
In article ,
Laurent Deniau wrote:
On 8 juin, 08:29, Pierre Maurette wrote:



En bref, il y les débutants et les bons.
Et le "programmeur moyen", qui a beaucoup de mal à comprendre et
surtout à comprendre qu'il ne devrait chercher à comprendre et qu'il
serait préférable qu'il ne programmât point.
Et puis il y a, non pas Frida, mais l'Enseignant, plus que bon et
n'ayant jamais débuté, bien que souvent n'ayant jamais quitté l'école.
L'Enseignant cultive au moins le paradoxe...
L'Enseignant préfère s'adresser à ses semblables et aux bons - et
encore... - qu'aux mauvais, aux moyens, et aux ... débutants ;-)


Tu sais, l'Enseignant est divers. Disons même qu'il y a diversité
d'enseignants.

J'aurais aimé quelque chose d'utile, genre règle de nommage pour les
types typedef-és malgré l'opposition de l'Enseignant. C'est pourtant
ici que j'avais appris que le suffixage par _t était *très* mal. Je
m'étais rabattu sur le prefixage Petrus_, mais ça ne convient pas
toujours. Et j'aimerais bien un truc qui indique que c'est un type.


Il y a la version Pascal
typedef struct file T_File;
moi, je préfère le côté Java/C++: ça commence simplement par
une majuscule
typedef struct File File;
Et puis ça permet de faire
File file;
mais je ne fais des typedef que sur des struct et les pointeurs
de fonctions (sur les ptr de fct, j'ai pas trouvé de règle de
nommage tres satisfaisante).

Après, jamais de typedef sur les tableaux.

Pour les TAD, je garde le typedef sur le struct, dans le même
genre que le FILE* (les majuscules en moins). Mais bon.

Mais pour ton pb, d'avoir un type sans padding, peut être ne
peut-on pas faire autrement que le typedef sur tableau. Le
langage C ne permet pas de tout bien faire. Il y a des
bonnes pratiques, pour les cas habituels. Mais dans ce cas,
je ne vois pas d'alternative.

Marc Boyer



Avatar
Thierry B
--{ Marc Boyer a plopé ceci: }--

Un commentaire sur le commentaire. Lorsque j'enseigne le C, je deconseille
toujours l'usage de typedef et l'usage de macros (*) aux debutants.

*: pour autre chose que de betes #define VALUE 42


Même un typedef sur des structs ?


Si, pour moi, celui-ci peut être bien, et même souvent,
comment dire, "clarifiant", à condition que le nom soit
bien choisi. Et _surtout_, de ne pas passer à la déclaration
d'un typedef pour les pointeurs sur la structure "typedéfée"
à l'étape précedente. Pour moi, un pointeur doit *toujours*
rester explicite. Bon, je ne suis pas une référence non
plus, c'est juste que je fonctionne comme ça :-(

Bof. Que le C permette de faire des horreurs, ça ne me semble pas
une nouveauté. De là à interdire le struct...


Retournons donc au BCPL...

--
A horse will do most of its maintenance itself, but it needs fuel even if
you're not using it.


Avatar
espie
In article ,
Pierre Maurette wrote:

En bref, il y les débutants et les bons.
Et le "programmeur moyen", qui a beaucoup de mal à comprendre et
surtout à comprendre qu'il ne devrait chercher à comprendre et qu'il
serait préférable qu'il ne programmât point.

Et puis il y a, non pas Frida, mais l'Enseignant, plus que bon et
n'ayant jamais débuté, bien que souvent n'ayant jamais quitté l'école.
L'Enseignant cultive au moins le paradoxe...


C'est pas exactement mon cas, ca fait maintenant une dizaine d'annees que
j'ai une vie double de developpeur et d'enseignant, hein... en particulier
en portant du code soit-disant portable sous OpenBSD (et j'en ai vu des
cas tordus, pendant ces dix ans).

Je peux etre un peu plus precis, si tu veux.

J'ai commence mes premiers cours a expliquer les choses tres en detail...
un peu trop en fait. Je me suis rendu compte que je `noyais' mes etudiants
sous trop d'explications. Faut voir ce qu'on veut leur apprendre aussi,
si c'est connaitre tous les points de detail du langage, ou si c'est savoir
ecrire des programmes C qui marchent. Dans le second cas, il suffit de
savoir `lire' des typedef, et de savoir dans quel contexte il est utile
d'en definir...

Le probleme d'un cours, c'est que la quantite d'explications donnee par
rapport a chaque element abordee n'est absolument pas proportionnelle a
son utilite pratique... On passe toujours plus de temps sur des points
de detail, ou sur des choses complexes qui ne servent que rarement.
typedef en fait partie. Je prefere passer plus de temps sur les bonnes
facons de nommer les fonctions et les variables.

Un autre exemple, qui correspond a des cours que je ne fais pas, c'est
celui du debutant en oriente-objet, qui a l'impression que le code qu'il
ecrit ne sera pas oriente-objet s'il n'utilise pas d'heritage... ce qui
fait que l'heritage est mis a toutes les sauces, et utilise allegrement
a la place de la composition et de la delegation... ou les gens a qui
ont a dit que les variables membres publics, c'etait mal, et donc qui
ecrivent des classes qui ne sont que des structures de donnees avec des
getter et setter pour tous les membres, y compris quand ca ne fait pas
de sens...


typedef, c'est du sucre syntaxique dans *enormement* de cas d'utilisations.
Dans tous ces cas, c'est preferable d'ecrire un truc legerement plus long,
mais qui va poser moins de soucis ensuite. Lorsque les etudiants me
demandent, j'explique pourquoi c'est une mauvaise idee, parce que j'ai
croise suffisamment d'exemples de code ou ca en etait une... mais en general,
c'est des problemes qui se posent lorsqu'on a 2000 ou 3000 lignes de code
(generalement, au moment ou c'est tres tard pour tout corriger).
C'est difficile de donner des exemples reduits. Les seuls bouquins que
je connais qui parlent du sujet proprement s'adressent a des programmeurs
C++ (le _large scale C++ software development_ de Lakos et la serie
_exceptional C++_ de Sutter).

La seule justification valable de typedef pour moi, c'est pour creer des
types abstraits qui facilitent la portabilite (comme size_t, ou pid_t par
exemple). Mais ca presente quand meme deux enormes problemes:
1/ deja ce ne sont pas de vrais types abstraits... un typedef est juste
un autre nom pour le type de depart... pas de verification et de warnings
du compilo...
2/ on envahit quand meme l'espace de nom global. Donc ces typedefs sont
a proscrire dans tout ce qui ressemble de pres ou de loin a un fichier
d'entete public (ou a utiliser avec extremement de parcimonie).

Il faut voir aussi qu'une enorme partie de l'activite de developpement est,
normalement, collaborative... ca vaut le coup d'ecrire du code qui soit
simplement lisible par d'autres... et les styles de codage C les plus
courants contiennent peu de typedef, justement parce que ca rend le
code plus dur a lire.

Pour revenir aux problemes 1/ et 2/, leurs consequences sont souvent
mal maitrisees... lorsqu'on lit du code, par exemple, on `voit' les typedef,
on ne vois pas les types sous-jacents. S'il y a un bug de definition quelque
part, on ne le verra qu'a l'execution. Je recommande par exemple de passer
un outil de verification de code sur des programmes C existants (un lint
correct). Ca donne souvent des choses tres eclairantes sur des typedef,
comme des problemes de comparaison signes/non signes, ou de taille maximale
du type... presque toujours, on se retrouve a revenir au type sous-jacent
pour comprendre ce qui se passe. Et la, le probleme apparait comme une
evidence.

Pour le deuxieme probleme, le code ne finit jamais la ou on s'attend. On se
dit toujours `mais ca, c'est un petit truc, donc je peux me permettre de
prendre des raccourcis, ca ne servira jamais a rien'.

La loi de Murphy aidant, le code en question est bien sur celui qui va
finir au coeur d'un logiciel de 30000 lignes, sans jamais avoir ete nettoye.

1 2 3 4