OVH Cloud OVH Cloud

Signature de struct

30 réponses
Avatar
Thierry Noc
Bonjour tlm,

Je rapplique avec une question pas très sexy, désolé.


Si j'ai une lib en C que je veux utiliser en C++, et que la lib n'a pas été
conçue pour C++, la solution est de retoucher les headers de la lib et de
rajouter des :
#ifdef __cplusplus
extern "C" {
#endif
dans tous les .h.

Si dans cette lib, y'a une struct avec un membre qui s'appelle operator. ex:

struct st {
int operator;
};

Est-ce que c'est correct de faire:

#ifdef __cplusplus
extern "C" {
#endif

struct st {
#ifdef __cplusplus
int xoperator; // operator est un mot clé réservé en C++
#else
int operator;
#endif
};

#ifdef __cplusplus
}
#endif

Autrement dit, est-ce que une structure n'aurait pas une espèce de signature
(comme une fonction) qui ferait intervenir le nom des membres, et qui
empêcherait de l'utiliser si on la falsifie. (d'après la norme, et d'après
la réalité du terrain).


Autre question:

sur un :
typedef char * charptr;
ou :
typedef struct st *structptr;

est-il nécessaire d'encadrer ces typedefs d'un extern "C" ?

--

10 réponses

1 2 3
Avatar
drkm
"Thierry Noc" writes:

"Loïc Joly" a écrit dans le message de
news:bk53g3$o3f$

Pour le posteur initial, une version vraiment propre consisterait
à écrire une couche d'interface pour cette bibliothèque en C
compatible C++, mais ça rajoute un niveau de complexité.


C'est impensable car en fait c'est pas une lib. Je rajoute des
modules C++ a une appli en C dont j'ai pas le source.


Mais si tu définis une couche d'interface en C, qui utilise
l'implémentation existante (avec `operator') et est destinée à être
utilisée par le code C++ (et sera donc « compatible » C et C++), quel
est le problème ?

--drkm


Avatar
Gabriel Dos Reis
"Thierry Noc" writes:

| "Gabriel Dos Reis" a écrit dans le message de
| news:
| > "Thierry Noc" writes:
| >
| >
| > C'est là où intervient l'ODR (One Definition Rule) qui dit que deux
| > classes sont les mêmes si et seulement si les suites de tokens en
| > correspondance biunivoque.
|
| et par 'token' on entend le type du membre et le nom du membre ?
| c'est a dire 'int' est un token et 'operator' aussi ?

yep.

tu peux éviter le « problème » en ne redéfinissant pas la structure dans
les programes C++. Mais de l'autre côté, c'est un abus répandu qui
« marche » dans la pratique.

-- Gaby
Avatar
Thierry Noc
"drkm" a écrit dans le message de news:

"Thierry Noc" writes:

"Loïc Joly" a écrit dans le message de
news:bk53g3$o3f$

Pour le posteur initial, une version vraiment propre consisterait
à écrire une couche d'interface pour cette bibliothèque en C
compatible C++, mais ça rajoute un niveau de complexité.


C'est impensable car en fait c'est pas une lib. Je rajoute des
modules C++ a une appli en C dont j'ai pas le source.


Mais si tu définis une couche d'interface en C, qui utilise
l'implémentation existante (avec `operator') et est destinée à être
utilisée par le code C++ (et sera donc « compatible » C et C++), quel
est le problème ?


En fait tu veux dire d'écrire une interface juste pour les fonctions
utilisant la struct en argument ou en retour.
Faut penser aussi a faire une interface pour l'accès aux données globales de
l'appli qui contiennent cette struct.
Ca me paraît tellement de boulot que j'ai du mal a cerner tout ce qu'il y
aurait a faire.



Avatar
drkm
"Thierry Noc" writes:

"drkm" a écrit dans le message de news:


Mais si tu définis une couche d'interface en C, qui utilise
l'implémentation existante (avec `operator') et est destinée à
être utilisée par le code C++ (et sera donc « compatible » C et
C++), quel est le problème ?


En fait tu veux dire d'écrire une interface juste pour les fonctions
utilisant la struct en argument ou en retour.


Tu ne peux pas inclure l'en-tête où est défini la structure. Il
faut donc fournir, s'il en a besoin, les fonctionalités de cet en-tête
à ton code C++. Tu crées donc un ensemble de fonctions et de types de
données qui agirons sur cette structure.

Le reste de l'application ne doit bien sûr pas être modifié, il
continue d'utiliser directement la structure. La couche d'indirection
que tu définis doit être en C, pour pouvoir utiliser la structure
incriminée, mais être également du C++ valide (sans utiliser
« operator », par exemple).

Faut penser aussi a faire une interface pour l'accès aux données
globales de l'appli qui contiennent cette struct. Ca me paraît
tellement de boulot que j'ai du mal a cerner tout ce qu'il y aurait
a faire.


Ca dépend. Avec des interfaces modulaires, il y a moyen de ne
fournir que quelques fonctions très simples. Avec des fichiers comme
ceux de GCC, puisque l'on en parlait dans ce thread, c'est un
cauchemard.

Mais dans ce genre de situation, c'est de toutes façons trop de
boulot, dans le sens où c'est un boulot qui aurait pû nous être évité
facilement.

--drkm


Avatar
Gabriel Dos Reis
drkm writes:

| Tu ne peux pas inclure l'en-tête où est défini la structure. Il
| faut donc fournir, s'il en a besoin, les fonctionalités de cet en-tête
| à ton code C++. Tu crées donc un ensemble de fonctions et de types de
| données qui agirons sur cette structure.

par exemple, dans l'en-tête en question, tu peux juste faire quelque
comme

#ifndef __cplucplus
extern "C" {
#endif
struct foo;
struct foo* make_foo(void);
void destroy_foo(struct foo*);
int bar(struct foo*, int, void*);
void* baz(FILE*, struct foo*);

#ifndef __cplucplus
} /* extern "C" */
#endif

et dans ta partie "C", tu définis la structure en question.

-- Gaby
Avatar
kanze
"Michaël Monerau" wrote in message
news:<V1o9b.149279$...
Gabriel Dos Reis wrote:
"Michaël Monerau" writes:

Plus sérieusement, on peut le vouloir dans le cas d'une lib qui
doit être accessible pour des programmeurs à la fois C et C++...
Mais alors, les headers seront utilisés pour des programmes
différents, qui auront des instances de compilations différentes,
et donc qui n'auront pas de problèmes d'ODR.


sauf que les programmes devront être linkés contre la bibliothèque,
qui en générale est unique. Donc, le programme C++ au final va
comprendre des bouts compilés avec un compilateurs C (la
bibliothèque) qui aura vu une définition différente de celle du
programme C++.


D'accord. Je n'avais pas pensé que l'ODR s'appliquait aussi aux
libraries contre lesquelles on linkait... Enfin, c'est logique
maintenant que j'y repense :)


Pas forcement. En tout cas, une chose est certaine. C'est qu'il n'y a
pas de ODR en C. Alors, au moins que C++ impose des règles à C, ce n'est
pas là le problème. Au moins si tous les composants C++ voient la même
chose.

En fait, dès que tu linkes un objet (qu'il provient d'une bibliothèque
ou non) généré d'un langage autre que le C++, tu as en quelque sort un
comportement indéfini à l'égard de la norme C++. Parce que le C++ ne
spécifie rien en ce qui concerne les autres langages. Le cas de C est un
peu spécial, parce que la norme C++ exige plus ou moins qu'un
compilateur C++ supporte la présence des appels à des fonctions C.

Comme j'ai dit, C n'a pas de ODR. Il a, en revanche, quelque chose de
semblable -- le concepte des types compatibles. Et pour que deux types
struct soient compatibles, il faut qu'ils aient le même nom, les mêmes
membres, dans le même ordre, avec les types compatibles et les mêmes
noms. C-à-d que ci certains composants C voyaient operator, et d'autres
xoperator, il y aurait aussi un comportement indéfini. Aujourd'hui --
dans une passée distante, C utilisait l'équivalence structurelle des
types. (Je ne me rappelle plus la situation dans C90, mais quand j'ai
appris le C, aux alentours de 1982, il utilisait l'équivalence
structurelle.) Or, selon les règles de l'équivalence, pour être
équivalent, il suffit que l'ordre et les types des éléments concorde :
struct Complex { double real ; double imag ; } ;
et
struct Point { double x ; double y ; } ;
sont des types équivalent (et passer un Point* à une function qui
s'attendait à un Complex* était tout à fait légal).

Or, il s'avère que les fournisseurs des compilateurs C ont du respect
pour leurs utilisateurs, et qu'ils évitent de casser leur code
inutilement. Le cas ci-dessus est devenu comportement indéfini par la
norme, mais comportement indéfini veut dire que les auteurs du
compilateur peuvent, tout en étant conforme, implémenter les anciennes
règles. Chose qu'ils ont fait, sans exception.

Alors, en supposant toujours que tous les composants C++ voient la même
chose, on a un comportement défini par l'implémentation (et non un
comportement indéfini, comme dit Gaby) dès qu'on utilise « extern "C" »,
mais que le but de l'« extern "C" » est clair, et que tous les
compilateurs C implément l'équivalence structurelle, et ne risquent pas
de changer à cause du code existant, je crois que la solution proposée
ne comporte aucune risque réel.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
Loïc Joly writes:

| Pour le posteur initial, une version vraiment propre consisterait à
| écrire une couche d'interface pour cette bibliothèque en C
| compatible C++, mais ça rajoute un niveau de complexité.

éviter le nom « operator » est plus simple.


Utiliser le nom « operator » dans du code C écrit aujourd'hui, c'est
effectivement irresponsible. En revanche, je m'en servais aussi tard que
1988, et je ne me sentais pas irresponsible. Et je me rappelle bien la
première fois que j'ai dû compiler un en-tête C avec un compilateur C++,
le compilateur a râlé à cause d'un membre « class ».

(Ceci dit, si j'étais pourvoyeur d'une bibliothèque C aujourd'hui, égal
quand la bibliothèque a été écrit, je me débrouillerais pour qu'aucun
symbol dans les en-têtes publics s'appelle operator, ni class, ni ...
Que du code ancien contient de telles choses, c'est normal, mais
l'effort de les enlever, au moins dans les interfaces, n'est vraiment
pas grand.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Gabriel Dos Reis
writes:

| Utiliser le nom « operator » dans du code C écrit aujourd'hui, c'est
| effectivement irresponsible. En revanche, je m'en servais aussi tard que
| 1988, et je ne me sentais pas irresponsible.

tu dis toi même avoir commencé C++ vers 1990 ; cela me semble normal.

-- Gaby
Avatar
Gabriel Dos Reis
writes:

| Pas forcement. En tout cas, une chose est certaine. C'est qu'il n'y a
| pas de ODR en C.

la norme C ne l'appelle pas comme cela, mais la notion de « quand deux
définitions » correspondent à la même entité existe en C. Je peux
l'appeler la règle de tartempion si cela te fait plaisir.

[...]

| Alors, en supposant toujours que tous les composants C++ voient la même
| chose, on a un comportement défini par l'implémentation (et non un
| comportement indéfini, comme dit Gaby)

C'est du fonctionnement indéfini, parce que « extern "C" » ne veut pas
dire, vous pouvez passer n'importe quoi. « extern "C" », ne veut pas
dire, on lève la vérification des contraintes.

| dès qu'on utilise « extern "C" »,
| mais que le but de l'« extern "C" » est clair, et que tous les
| compilateurs C implément l'équivalence structurelle, et ne risquent pas
| de changer à cause du code existant,

cela a probablement dû s'afficher dans la même couleur que le fond de
ton lecteur de messages, mais j'ai précisé que c'était une pratique
répandue mais incorrecte.

-- Gaby
Avatar
Thierry Noc
"Richard Delorme" a écrit dans le message de news:
3f67005f$0$20942$

Utiliser les mots clés du C++ (class, this, operator, ...) dans du C est
toujours un plaisir malin pour certains. Ce n'est pas de
l'irresponsabilité, mais une volonté d'affirmer avec une certaine et
stupide constance, que C et C++ sont deux langages différents et
incompatibles.


Je sais pas vous mais moi ca m'arrive encore d'appeler des variables 'new'.
ex: bool new = true;
Et je suis toujours aussi surpris que ca ne compile pas.

Donc y'a peut être quelque mauvaises graines qui font les malins, mais je
pense que dans la plupart des cas c'est soit de l'étourderie, soit tout
simplement de l'ignorance (y'a bien des programmeurs C qui n'ont aucune
notion de C++).

1 2 3