Question about C/C++ struct memory layout compatibility

  • Thread starter Vincezo Ciaschini
  • Start date
V

Vincezo Ciaschini

Supposing you have the following declaration in a header file:
-- head.h --

struct s {
int c;
char v;
#if defined(__cplusplus)
s();
s(double);
method1(int);
method2(float);
#endif
};

and then two sources,

-- cppsrc.cc --
#include "head.h"

extern "C" {
s *create(void)
{
s *res = new s(1.0);
res->method1(4);
return res;
}

-- csrc.c --
#include "head.h"

extern struct s *create(void);

int f()
{
struct s* val = create();
val->v = 'd';
}

Is this legal/portable?

Thanks in advance,
Vincenzo
 
V

Victor Bazarov

Vincezo said:
Supposing you have the following declaration in a header file:
-- head.h --

struct s {
int c;
char v;
#if defined(__cplusplus)
s();
s(double);
method1(int);
method2(float);
#endif
};

and then two sources,

-- cppsrc.cc --
#include "head.h"

extern "C" {
s *create(void)
{
s *res = new s(1.0);
res->method1(4);
return res;
}

-- csrc.c --
#include "head.h"

extern struct s *create(void);

int f()
{
struct s* val = create();
val->v = 'd';
}

Is this legal/portable?

I have no definite answer to this question. I believe, though, that
it would be implementation-specific. However, regardless of what I
believe, I'd like to know *why* would you want to do something like
that. Why do you feel the need to have both C and C++ translation units
in the same program?

V
 
S

Shezan Baig

Vincezo said:
Supposing you have the following declaration in a header file:
-- head.h --

struct s {
int c;
char v;
#if defined(__cplusplus)
s();
s(double);
method1(int);
method2(float);
#endif
};

and then two sources,

-- cppsrc.cc --
#include "head.h"

extern "C" {
s *create(void)
{
s *res = new s(1.0);
res->method1(4);
return res;
}

-- csrc.c --
#include "head.h"

extern struct s *create(void);

int f()
{
struct s* val = create();
val->v = 'd';
}

Is this legal/portable?


I don't think so. I believe it violates the One Definition Rule. But
I'm not sure if this applies when mixing C and C++.

-shez-
 
V

Vincezo Ciaschini

Victor said:
I have no definite answer to this question. I believe, though, that
it would be implementation-specific. However, regardless of what I
believe, I'd like to know *why* would you want to do something like
that. Why do you feel the need to have both C and C++ translation units
in the same program?
Because they would not be in the same program. The cppsrc.cc would be
in a dynamic library that will be linked to the program containing
csrc.c. It is an effort to provide a C interface to a C++ library.

Bye,
Vincenzo
 
V

Vincezo Ciaschini

Shezan said:
I don't think so. I believe it violates the One Definition Rule. But
I'm not sure if this applies when mixing C and C++.
My doubt exactly, especially considering that the two definition are
identical with respect to the included data.

It seems reasonable to me that, if the data definition part is
identical, and there is no virtual/RTTI on the C++ part, that the memory
layout should be identical. However, I am not certain about this.

Also, the cppsrc.cc code will be in a library linked by the csrc.c (and
a main() function) code.

Bye,
Vincenzo
 
S

Shezan Baig

Vincezo said:
Because they would not be in the same program. The cppsrc.cc would be
in a dynamic library that will be linked to the program containing
csrc.c. It is an effort to provide a C interface to a C++ library.



You probably need to make a clean-cut between the C++ interface and the
C interface, instead of attempting to mix them both in a single header
file. Use 2 header files:

head.h
 
V

Victor Bazarov

Vincezo said:
Victor Bazarov wrote:
[...] I'd like to know *why* would you want to do something like
that. Why do you feel the need to have both C and C++ translation units
in the same program?

Because they would not be in the same program. The cppsrc.cc would be
in a dynamic library that will be linked to the program containing
csrc.c.

Read your own statement again. If it is _linked_, it's in the same
program. By definition.
It is an effort to provide a C interface to a C++ library.

I don't see any need to have a C struct created in C++ code and returned
by a C function. It would be best to de-couple them altogether and use
some kind of "handle" to identify your C++ object inside your C++ space.
Your library is the only thing that should know about the inner workings
of that object. The outside world should use the C interface to do all
the processing. Passing the "handle" back and forth is the only answer
AFAIK.

<offtopic> But is it really needed to have C interface? How many
customers do you have that use C versus C++ bindings? Any at all?
Never mind. Marketing decisions are not necessarily based on common
sense. And don't tell me that having a C interface is not a marketing
decision.
</offtopic>

V
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Vincezo said:
It seems reasonable to me that, if the data definition part is
identical, and there is no virtual/RTTI on the C++ part, that the memory
layout should be identical. However, I am not certain about this.

I think is unreasonable to worry about that. Just write a class that derives
from or contains the C style struct and use it from C++.
 
S

Shezan Baig

Victor said:
<offtopic> But is it really needed to have C interface? How many
customers do you have that use C versus C++ bindings? Any at all?
Never mind. Marketing decisions are not necessarily based on common
sense. And don't tell me that having a C interface is not a marketing
decision.
</offtopic>


Sometimes it is just a case that certain developers at the company who
are "afraid" to use C++. Sounds silly, yes. But we all cannot control
everybody :(

-shez-
 
P

Pete Becker

Victor said:
And don't tell me that having a C interface is not a marketing
decision.

It's often a sensible engineering decision. C interfaces are far less
dependent on the compiler you're using than C++ interfaces, so a shared
library with a C interface is more broadly useful than a shared library
with a C++ interface. Having a well-defined C++ ABI for the platform
you're targeting makes this less of a problem, to the extent that the
ABI really is well-defined.
 
R

Rapscallion

Vincezo said:
Supposing you have the following declaration in a header file:
-- head.h -- ....

Is this legal/portable?

Maybe. But the classic way to provide a C interface for a C++ program
goes like this:

// somefile.h ----------------------
struct s; // declaration

extern "C" {
struct s *create(void);
void destroy (struct s* x);
void method1 (struct s* x, int);
// ...
}


// somefile.cpp --------------------
struct s {
s();
s(double);
method1(int);
method2(float);
private:
int c;
char v;
};

s *create(void)
{
struct s *res = new s(1.0);
res->method1(4);
return res;
}

void destroy (struct s* x) { ... }
void method1 (struct s* x, int) { ... }


// the C user ------------------------
int main() {
struct s* val = create();
method1 (s, 33);
destroy (s);
}
 
A

Andre Kostur

I have no definite answer to this question. I believe, though, that
it would be implementation-specific. However, regardless of what I
believe, I'd like to know *why* would you want to do something like
that. Why do you feel the need to have both C and C++ translation units
in the same program?

Arguably wouldn't that violate the One Definition Rule ?
 
R

Rene Moehring

Maybe. But the classic way to provide a C interface for a C++ program
goes like this:

// somefile.h ----------------------
struct s; // declaration

extern "C" {
struct s *create(void);
void destroy (struct s* x);
void method1 (struct s* x, int);
// ...
}


// somefile.cpp --------------------
struct s {
s();
s(double);
method1(int);
method2(float);
private:
int c;
char v;
};

s *create(void)
{
struct s *res = new s(1.0);

This new could throw an exception. You should use the one that returns a
NULL pointer on error and handle that case.
 
R

Rapscallion

Rene said:
On 9 Jun 2005 08:37:17 -0700, Rapscallion wrote: ....

This new could throw an exception. You should use the one that returns a
NULL pointer on error and handle that case.

Good point. Not only new may throw but also 'res->method1(4)'. One
needs to surround function bodies with try {} catch (...){} blocks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top