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

tableau à 0 élément

22 réponses
Avatar
Thomas Nemeth
Bonjour,

Je parcourais un site web ce matin et je suis tombé sur un extrait
des nouveautés dans un noyau unix très répandu :

struct sg_ring
{
struct list_head list;
unsigned int num, max;
struct scatterlist sg[0];
};

Je me demande, dans cette structure, ce que signifie ce tableau
à 0 élément... Le K&R spécifie que, je cite :
"Dans une déclaration T D où D est de la forme
D1[expression-constante/opt/]
[...]
Si une expression constante est présente, elle doit être du type
entier et de valeur supérieure à 0."

Je suis perplexe... Quelqu'un a-t-il une solution/explication ?


Thomas.

10 réponses

1 2 3
Avatar
espie
In article ,
Thierry B. wrote:
--{ Marc Espie a plopé ceci: }--

un nombre d'éléments à 1, pour éviter les roumaigailles de certains
compilateurs. Voilà, c'est confortable, non_casher et dangeureux.


Avec la taille du tableau a 1, ca n'a rien de dangereux, et les compilo
ne ralent pas.


Par "dangeureux", je voulais dire que la moindre erreur dans la
traçabilité du nombre d'éléments (ré)alloués dans la partie à
taille variable est parfois épuisante à débugger. Sans compter
les pointeurs qui apprennent la danse du ventre :)


Dans ce cas-la, tout C est dangereux.

Les regles du C sont explicitement concues pour que ca fonctionne.


_Tout_ fonctionne en C, mais parfois on ne sait plus ce que ça fait.


Non, tout ne fonctionne pas. Il y a des trucs qui sont fortement non
portables. Il y a aussi des choses qui sont effroyablement compliquees,
voire qui ne fonctionnent pas du tout.

Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?



Avatar
Aris
Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?


oui, mais il faut utiliser la fonction qui prend une va_list comme
vprintf. Je pense que générer une va_list c'est faisable et peut-être
même portable.

si la fonction n'est pas disponible avec une va_list, en effet du C tout
seul ne fonctionnera pas (quoi qu'il y a moyen de tricher en mettant les
arguments en tant que variables locales, juste avant l'appel de
fonction. C'est degueu et ça risque de sauter à l'optimisation)

Avatar
espie
In article <47891b73$0$32003$,
Aris wrote:

Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?


oui, mais il faut utiliser la fonction qui prend une va_list comme
vprintf. Je pense que générer une va_list c'est faisable et peut-être
même portable.


Ah oui ? ben moi j'ai des doutes serieux.


Avatar
Aris
In article <47891b73$0$32003$,
Aris wrote:
Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?
oui, mais il faut utiliser la fonction qui prend une va_list comme

vprintf. Je pense que générer une va_list c'est faisable et peut-être
même portable.


Ah oui ? ben moi j'ai des doutes serieux.
je retire ce que j'ai dis, sans hacker la structure va_arg à la hache

c'est impossible. Reste que sur un même processeur mais avec des OS
différents je peux trouver un moyen bourrin de le faire



Avatar
Antoine Leca
En news:47895b8c$0$32000$, Aris va escriure:
Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de
fonction avec nombre arbitraire de parametres (autrement qu'avec
un switch, forcement limite a 10 ou 15 parametres) ?




Reste que sur un même processeur mais avec des OS
différents je peux trouver un moyen bourrin de le faire


Que nenni. Ce n'est pas le processeur qui définit la forme de valist/va_arg
(qui est ce qui est réellement importe ici), mais la définition de
l'interface applicative « binaire » (ABI en anglais).

Or, celle-ci n'est pas forcément unique pour un processeur donné.
Exemple 1 : le Motorola 68000 fut utilisé en mode 16 bits et en mode 32 bits
; pas beaucoup de chance de traiter ce genre de différence autrement que par
un cas partitulier.
Exemple 2 : x86-64 : l'ABI « Unix » (utilisé avec Linux, pour prendre
l'exemple le plus répandu) est subtilement différente de l'ABI Win64, par
exemple ce ne sont pas les mêmes registres qui sont utilisés...
Exemple 3 : l'architecture processeur PowerPC est (était) utilisé à la fois
dans des Macintoshs et dans des AS/400 (petits mainframes d'IBM). Mais
aucune chance de passer un programme binaire de l'un à l'autre :-)
D'autres exemples sont les processeurs qui peuvent changer de sens
d'adressage au démarrage, ou que sais-je encore ?


Antoine




Avatar
Erwan David
"Antoine Leca" écrivait :

Exemple 3 : l'architecture processeur PowerPC est (était) utilisé à la fois
dans des Macintoshs et dans des AS/400 (petits mainframes d'IBM). Mais
aucune chance de passer un programme binaire de l'un à l'autre :-)
D'autres exemples sont les processeurs qui peuvent changer de sens
d'adressage au démarrage, ou que sais-je encore ?


Sur H8SX une option du compilateur permet de choisir si on utilise 2 ou
3 registres pour passer les arguments (les autres sur la pile). Bien
entendu une lib compilée dans un mode est incompatbile avec un programme
compilé dans l'autre...

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé

Avatar
Aris
En news:47895b8c$0$32000$, Aris va escriure:
Et il y a meme quelques trucs que C ne sait pas faire.
Tu veux un exemple ? est-ce que tu sais *generer* un appel de
fonction avec nombre arbitraire de parametres (autrement qu'avec
un switch, forcement limite a 10 ou 15 parametres) ?




Reste que sur un même processeur mais avec des OS
différents je peux trouver un moyen bourrin de le faire


Que nenni. Ce n'est pas le processeur qui définit la forme de valist/va_arg
(qui est ce qui est réellement importe ici), mais la définition de
l'interface applicative « binaire » (ABI en anglais).

oui oui bien sur, je connais de mémoire les abi pour x86 et amd64 et

elles ne sont pas les mêmes. Je parlais plutot d'émuler des parametres
sur le stack avant l'appel de fonction, et compter sur le fait que la
fonction à params illimité va déborder sur le stack (exactement le meme
principe que lors de l'exploitation d'une faille format string). En tout
cas pour x86.
pour amd64, c'est un peu plus compliqué, il faut remplir les registres à
la main avec de l'assembleur inline. Et on sort du cadre du C pur





Avatar
Antoine Leca
En news:478ba348$0$32007$, Aris va escriure:
pour amd64, c'est un peu plus compliqué, il faut remplir les
registres à la main avec de l'assembleur inline.


Et même comme cela, ce n'est pas suffisant. Sur Linux, tu dois remplir
certains registres. Pour Windows, d'autres (et non, je n'ai envie de
chercher maintenant lesquels). Tout cela sur le même processeur, dans le
même mode « 64 bits », en utilisant éventuellement le même compilateur (ce
n'est pas le cas à ma connaissance pour x86-64, mais il y a d'autres cas
similaires où le compilateur C connaît plusieurs interfaces binaires).

Tu me diras, il y a d'autres différences (genre les long sur 64 ou 32 bits
respectivement) entre les deux interfaces, qui font que cette différence-là
est anecdotique...


Antoine

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

Et il y a meme quelques trucs que C ne sait pas faire.


Pour le café, je sais qu'il faut utiliser Emacs :)

Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?


Alors là oui, je veux bien l'exemple. Autant j'ai déja écrit des
fonctions qui prennent un nombre variable d'arguments (et à chaque
fois, j'ai du replongé dans les manpages :), autant un "appel de
fonction avec nombre arbitraire de paramètres", j'ai un peu de mal
à visualiser ce que ça peut être en pratique...

Et je ne comprends pas non plus le truc du switch qui limite !-)


--
fsck, fsck, fsck.
trois fois, adjugé le crash disque au bofh du fond.

Avatar
espie
In article ,
Thierry B. wrote:
--{ Marc Espie a plopé ceci: }--

Et il y a meme quelques trucs que C ne sait pas faire.


Pour le café, je sais qu'il faut utiliser Emacs :)

Tu veux un exemple ? est-ce que tu sais *generer* un appel de fonction
avec nombre arbitraire de parametres (autrement qu'avec un switch,
forcement limite a 10 ou 15 parametres) ?


Alors là oui, je veux bien l'exemple. Autant j'ai déja écrit des
fonctions qui prennent un nombre variable d'arguments (et à chaque
fois, j'ai du replongé dans les manpages :), autant un "appel de
fonction avec nombre arbitraire de paramètres", j'ai un peu de mal
à visualiser ce que ça peut être en pratique...


Le plus souvent: un intermediaire qui prend une liste plus ou moins
arbitraire de parametres, qui les modifie et qui les passe a la vraie
fonction. C'est d'ailleurs pour ca qu'on a des variantes de la plupart
des fonctions a nombre variable de parametres (printf -> vprintf,
exec -> execve) sur un systeme raisonnable: on sait recuperer le nombre
variable de parametres, mais on ne sait pas le passer plus ou moins
tel quel a la fonction appelee.

On peut s'en sortir avec un switch, en gros:

switch(n)
{
case 0:
f();
break;
case 1:
f(a[0]);
break;
case 2:
f(a[0], a[1]);
break;
...
}

mais le switch sera forcement fini, et donc ca s'arretera a 10 ou 15
parametres.


Ce genre de trucs est utile, par exemple, pour faire de la delegation.

On a une fonction appelee avec une collection de parametres, et on
aimerait bien tout passer en bloc a une autre fonction, qui sera
responsable du calcul. On aimerait bien faire ca sans avoir a definir
quoi que ce soit, mais en C portable, il n'y a pas le choix, on est
bon pour se definir sa structure de `parametres d'appels' et n'utiliser
que des fonctions qui utilisent cette structure.

Par exemple, en perl, on peut ecrire:

sub f
{
&g;
}

avec comme convention que dans ce cas precis, g prendra exactement les
parametres de g, quels qu'ils soient. Ou bien, pour des cas un peu moins
pathologiques.

sub f
{
my ($self, @l) = @_;

g(2, @l);
}

ici, on extrait un parametre distingue (le premier) et on appelle g avec
une liste reconstruite.


1 2 3