OVH Cloud OVH Cloud

Les structures à taille variables sont elles portables ?

27 réponses
Avatar
Luc de Bauprois
Bonjour

Le code suivant est il portable :

-----------------------------------------------------------------------
struc machin
{
// Autres memebre virés pour plus de clarté

char string[1]; // dernier membre de la struct
};

puis faire des allocation du style

struct machin *s = (struct machin *)malloc( sizeof( struct machin) +
strlen(chaine));

.../...

strcpy( s->chaine, chaine );
-----------------------------------------------------------------------

Ca alloue des struct de taille variable, en laissant de la place "à la
fin" pour écrire le contenu dans la châine.

Est ce "propre" ? Normalisé ? Portable ? Ou y a t'il des effets de bord
pervers qui vont provoquer un merdier indemerdable plus tard ?

Merci

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Jean-Marc Bourguet wrote:

Au fait, est-ce qu'il y a quelque chose de public sur OOC?


Non. Je n'ai jamais fini de le 'nettoyer'. Je peux mettre un tarball
sur le web du code qui compile. Les modules (Unitest, ODBC, etc...)
n'ont jamais ete mis a jour sur la derniere version et depuis je
suis passe a COS ou je suis entrain de finalise le core. Ensuite je
migrerais pas mal de code de OOC vers COS.


Quand tu sorts quelque chose, tu nous fais signe? Je doute que je
fasse quoi que ce soit d'autre que de regarder.

La derniere fois que j'ai regarde, ta page n'avait que des choses
sur OOPC.


Yep. Parce que ecrire de la doc prend plus de temps que d'ecrire du code ;-)


Je suis au courant. Mais vu que sur la page que je connais, il n'y a
apparemment rien de posterieur a 2001 ou 2002, je me demandais si
j'avais loupe un autre point d'acces plus recent.

A+

--
Jean-Marc


Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Jean-Marc Bourguet wrote:
Luc de Bauprois writes:

Est ce "propre" ? Normalisé ? Portable ? Ou y a t'il des effets de bord
pervers qui vont provoquer un merdier indemerdable plus tard ?
À ma connaissance, c'est du comportement indéfini, en C90 comme en C99.



Absolument.


On en parle justement dans le fil auquel je faisais allusion sur
comp.std.c. Sujet: Out-of-bounds nonsense. Utiliser "struct hack"
pour rafiner la recherche.

A+

--
Jean-Marc



Avatar
espie
In article <ein1h5$7ba$,
Laurent Deniau wrote:
Jean-Marc Bourguet wrote:
Luc de Bauprois writes:


Est ce "propre" ? Normalisé ? Portable ? Ou y a t'il des effets de bord
pervers qui vont provoquer un merdier indemerdable plus tard ?



À ma connaissance, c'est du comportement indéfini, en C90 comme en C99.


Absolument.


Effectivement, j'ai ete trop vite en besogne, c'est juste `bloque' par
une petite entree assassine qui regimente ce qui se passe pour
*(a+i) lorsque a n'est pas un pointeur quelconque, mais un pointeur sur
une entree de tableau.

A mon avis, C99 a fait une grosse connerie. Il s'agit d'un idiome
super-frequent, qui marche sur a peu pres tout ce qui existe... On avait
deja tout ce qu'il faut pour le rendre legal (tous les paragraphes qui
visent a bien expliquer que char* sert a acceder a de la memoire, et qu'on
gicle tous les dispositifs de typage et d'optimisation lies a ca).

A la place, se contenter de rajouter une nouvelle syntaxe etait
foncierement debile: du coup, on se retrouve a coder des trucs moins
portables, puisqu'ils necessitent un compilo C99, ou a supposer qu'on
a un compilo qui accepte `cette extension'.

Pour ma part, je vais continuer a utiliser cet idiome classique, quitte
a gueuler comme un putois si d'aventure, un jour, la dreamteam GCC decide
de supprimer le support de cette extension...



Avatar
Laurent Deniau
Eric Levenez wrote:
Le 4/11/06 13:41, dans , « Jean-Marc


(Marc Espie) writes:


Est ce "propre" ? Normalisé ? Portable ? Ou y a t'il des effets de bord
pervers qui vont provoquer un merdier indemerdable plus tard ?


C'est propre, normalise, et portable.


Référence? Pourquoi alors a-t'on introduit les flexible array members?



Parce que c'est une écriture plus propre que de mettre un tableau de 1
élément. Pour calculer la taille de l'en-tête il fallait faire un sizeof
moins 1.


ou utiliser offsetof.

a+, ld.




Avatar
Eric Levenez
Le 6/11/06 16:42, dans <einl5a$hed$, « Laurent Deniau »
a écrit :

Eric Levenez wrote:

Parce que c'est une écriture plus propre que de mettre un tableau de 1
élément. Pour calculer la taille de l'en-tête il fallait faire un sizeof
moins 1.


ou utiliser offsetof.


Oui, mais on utilise sizeof pour avoir la taille de tous les objets C, sauf
là ou ce serait offsetof... ce n'est quand même pas très joli. :-)

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
espie
In article <C17538AB.8E48D%,
Eric Levenez wrote:
Le 6/11/06 16:42, dans <einl5a$hed$, « Laurent Deniau »
a écrit :

Eric Levenez wrote:

Parce que c'est une écriture plus propre que de mettre un tableau de 1
élément. Pour calculer la taille de l'en-tête il fallait faire un sizeof
moins 1.


ou utiliser offsetof.


Oui, mais on utilise sizeof pour avoir la taille de tous les objets C, sauf
là ou ce serait offsetof... ce n'est quand même pas très joli. :-)


Bah, si on veut vraiment savoir ou comment le tableau, il faut utiliser
offsetof... parce que sizeof va donner la taille de l'objet, et donc une
estimation conservative de la position de l'entete.

De fait, si on alloue la memoire a coup de sizeof modifie, on va parfois
allouer `un peu plus' que necessaire. Si on veut vraiment calculer
au plus juste, faudrait utiliser offsetof, ajouter le nombre de
caracteres voulus, et augmenter a sizeof si on est en dessous. ;-)



Avatar
Laurent Deniau
Eric Levenez wrote:
Le 6/11/06 16:42, dans <einl5a$hed$, « Laurent Deniau »


Eric Levenez wrote:

Parce que c'est une écriture plus propre que de mettre un tableau de 1
élément. Pour calculer la taille de l'en-tête il fallait faire un sizeof
moins 1.


ou utiliser offsetof.



Oui, mais on utilise sizeof pour avoir la taille de tous les objets C, sauf
là ou ce serait offsetof... ce n'est quand même pas très joli. :-)


Ah?

// interface.h
struct T {
size_t n;
#if ISO_C99
char t[];
#elif ISO_C89
char t[1];
#elif __GNUC__
char t[0];
#else
#error not supported
#endif
};

// implementation.c
struct T *tab = malloc(offsetof(struct T, t) + n*sizeof *tab->t);

Peux-tu reecrire cette ligne uniquement avec sizeof pour voir si c'est
plus joli?

a+, ld.



Avatar
Eric Levenez
Le 6/11/06 19:36, dans <einvba$lm8$, « Laurent Deniau »
a écrit :

// interface.h
struct T {


Je n'utilise les majuscules que pour les noms pour le préprocesseur.

size_t n;
#if ISO_C99
char t[];
#elif ISO_C89


ISO_C99 et ISO_C89 ne sont pas standard et même avec un compilateur conforme
cela ne donnera rien. Tu as quelque chose contre __STD_VERSION__ ?

char t[1];
#elif __GNUC__


Dès que l'on utilise une spécificité de GCC, "c'est mal".

char t[0];
#else
#error not supported


Ou mauvais define :-)

#endif
};

// implementation.c
struct T *tab = malloc(offsetof(struct T, t) + n*sizeof *tab->t);

Peux-tu reecrire cette ligne uniquement avec sizeof pour voir si c'est
plus joli?


Oui, sans problème :

struct t {
size_t n;
char t[];
};

struct t *tab = malloc(sizeof *tab + n * sizeof *tab->t);

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

Avatar
Laurent Deniau
Eric Levenez wrote:
Le 6/11/06 19:36, dans <einvba$lm8$, « Laurent Deniau »


// interface.h
struct T {



Je n'utilise les majuscules que pour les noms pour le préprocesseur.


Il se trouve que c'est justement un nom pour le preprocesseur, ce code
est extrait d'une interface 'generique'.

J'ai poste cette interface recemment sur comp.lang.c dans le thread
'Extremly fast dinamic array implementation'

size_t n;
#if ISO_C99
char t[];
#elif ISO_C89



ISO_C99 et ISO_C89 ne sont pas standard et même avec un compilateur conforme
cela ne donnera rien. Tu as quelque chose contre __STD_VERSION__ ?


Oui, parce que je ne me souvient jamais du mois. J'ai toujours un
fichier de setup qqpart qui detecte le niveau d'ISO compatibilite du
compilateur et le met dans ISO_C et je le compare au valeur du standard
mise dans ISO_C89, ISO_C94, ISO_C99.

Mais j'aurais du ecrire ISO_C >= ISO_C99 etc...

char t[1];
#elif __GNUC__



Dès que l'on utilise une spécificité de GCC, "c'est mal".


Ah? Qu'est ce que tu as contre gcc?

char t[0];
#else
#error not supported



Ou mauvais define :-)


? quel define?

#endif
};

// implementation.c
struct T *tab = malloc(offsetof(struct T, t) + n*sizeof *tab->t);

Peux-tu reecrire cette ligne uniquement avec sizeof pour voir si c'est
plus joli?



Oui, sans problème :

struct t {
size_t n;
char t[];
};

struct t *tab = malloc(sizeof *tab + n * sizeof *tab->t);


gcc -stdÈ9 -pedantic -W -Wall ton_exemple.c

ne compile pas. Il me semble avoir vu le mot 'portable' dans le titre du
thread. Une autre proposition ;-)

a+, ld.


Avatar
Eric Levenez
Le 7/11/06 10:35, dans <eipk1d$92h$, « Laurent Deniau »
a écrit :

Eric Levenez wrote:
Le 6/11/06 19:36, dans <einvba$lm8$, « Laurent Deniau »

// interface.h
struct T {


Je n'utilise les majuscules que pour les noms pour le préprocesseur.


Il se trouve que c'est justement un nom pour le preprocesseur, ce code
est extrait d'une interface 'generique'.


Moins on utilise le préprocesseur pour les defines ou macros, mieux cela
vaut.

J'ai poste cette interface recemment sur comp.lang.c dans le thread
'Extremly fast dinamic array implementation'


Et alors ?

size_t n;
#if ISO_C99
char t[];
#elif ISO_C89


ISO_C99 et ISO_C89 ne sont pas standard et même avec un compilateur conforme
cela ne donnera rien. Tu as quelque chose contre __STD_VERSION__ ?


Oui, parce que je ne me souvient jamais du mois. J'ai toujours un
fichier de setup qqpart qui detecte le niveau d'ISO compatibilite du
compilateur et le met dans ISO_C et je le compare au valeur du standard
mise dans ISO_C89, ISO_C94, ISO_C99.

Mais j'aurais du ecrire ISO_C >= ISO_C99 etc...


Tu aurais pu, mais même ainsi ISO_C n'est pas défini et non standard.

char t[1];
#elif __GNUC__



Dès que l'on utilise une spécificité de GCC, "c'est mal".


Ah? Qu'est ce que tu as contre gcc?


Quand on utilise ses "extensions" on se limite et on essaye d'imposer aux
autres ce compilateur.

char t[0];
#else
#error not supported


Ou mauvais define :-)


? quel define?


Voir plus haut.

#endif
};

// implementation.c
struct T *tab = malloc(offsetof(struct T, t) + n*sizeof *tab->t);

Peux-tu reecrire cette ligne uniquement avec sizeof pour voir si c'est
plus joli?


Oui, sans problème :

struct t {
size_t n;
char t[];
};

struct t *tab = malloc(sizeof *tab + n * sizeof *tab->t);


gcc -stdÈ9 -pedantic -W -Wall ton_exemple.c

ne compile pas.


On peut toujours lancer le compilateur avec des options imposant les
anciennes normes. Cela apporte quoi au débat ?

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.



1 2 3