Same structures, different names

B

Ben Bacarisse

DSF said:
I have a situation where I have two structures that are identical
except for the names. A simplified example:

struct foo
{
unsigned long a;
unsigned long b;
};

struct bar
{
unsigned long a;
unsigned long b;
};

I don't have the ability to re-designate either of them, as they
each belong to a different library.

So if I need to pass a function in library "foo" a "bar" variable, I
must create a "foo" variable and copy each member from the "bar"
variable to it. This is not my idea of efficiency.

I figure the answer's one of two things: It's either something I've
missed/forgotten, or it can't be done and I'm SOL.

Can you declare a union and put both structures in it like this:

union foobar {
struct foo foo;
struct bar bar;
} u;

? Then you can use u.foo as a struct foo and u.bar as the same data
interpreted as a struct bar.
 
D

DSF

Hello,

I have a situation where I have two structures that are identical
except for the names. A simplified example:

struct foo
{
unsigned long a;
unsigned long b;
};

struct bar
{
unsigned long a;
unsigned long b;
};

I don't have the ability to re-designate either of them, as they
each belong to a different library.

So if I need to pass a function in library "foo" a "bar" variable, I
must create a "foo" variable and copy each member from the "bar"
variable to it. This is not my idea of efficiency.

I figure the answer's one of two things: It's either something I've
missed/forgotten, or it can't be done and I'm SOL.

Thanks!

DSF
 
J

jens

Hello,

  I have a situation where I have two structures that are identical
except for the names.  A simplified example:

 struct foo
 {
   unsigned long a;
   unsigned long b;
 };

 struct bar
 {
   unsigned long a;
   unsigned long b;
 };

  I don't have the ability to re-designate either of them, as they
each belong to a different library.

  So if I need to pass a function in library "foo" a "bar" variable,


int func_w_foo_arg( struct foo *f ) { (...) };


int caller(void)
{
struct bar b;

(...)

func_w_foo_arg( (struct foo *) &b );


}
 
T

Tom St Denis

Hello,

  I have a situation where I have two structures that are identical
except for the names.  A simplified example:

 struct foo
 {
   unsigned long a;
   unsigned long b;
 };

 struct bar
 {
   unsigned long a;
   unsigned long b;
 };

  I don't have the ability to re-designate either of them, as they
each belong to a different library.

  So if I need to pass a function in library "foo" a "bar" variable, I
must create a "foo" variable and copy each member from the "bar"
variable to it.  This is not my idea of efficiency.

  I figure the answer's one of two things: It's either something I've
missed/forgotten, or it can't be done and I'm SOL.

Why would you create two identical but differently named structs? To
me, *THAT* is your inefficiency.

Tom
 
D

David Resnick

Why would you create two identical but differently named structs?  To
me, *THAT* is your inefficiency.

Tom

As OP said, they are in libraries that are out of his control.
Sometimes you just have to deal with what is. Haven't you ever had to
deal with an interface you didn't like but was frozen?

-David
 
K

Keith Thompson

DSF said:
I have a situation where I have two structures that are identical
except for the names. A simplified example:

struct foo
{
unsigned long a;
unsigned long b;
};

struct bar
{
unsigned long a;
unsigned long b;
};

I don't have the ability to re-designate either of them, as they
each belong to a different library.

So if I need to pass a function in library "foo" a "bar" variable, I
must create a "foo" variable and copy each member from the "bar"
variable to it. This is not my idea of efficiency.

I figure the answer's one of two things: It's either something I've
missed/forgotten, or it can't be done and I'm SOL.

It might be helpful to have some more information about the actual
structures. (I presume they aren't really called "foo" and "bar".)

You've shown us two struct types with exactly the same members
(same member names and types). Do these two libraries really
declare identical types? Are they certain to remain identical in
future versions of both libraries? Is the layout of both structures
imposed by some external interface?

Why does it make sense to pass a "bar" variable to a function in the
"foo" library?

"Data, data, data! I cannot make bricks without clay!"
 
M

Morris Keesan

int func_w_foo_arg( struct foo *f ) { (...) };


int caller(void)
{
struct bar b;

(...)

func_w_foo_arg( (struct foo *) &b );


}

Or, if you really need to pass the actual struct and not a pointer to it,
func_w_foo_arg(*(struct foo *)&b);
 
B

Ben Bacarisse

Kenneth Brody said:
DSF said:
I have a situation where I have two structures that are identical
except for the names. A simplified example:

struct foo
{
unsigned long a;
unsigned long b;
};

struct bar
{
unsigned long a;
unsigned long b;
};

I don't have the ability to re-designate either of them, as they
each belong to a different library.
[...]
Can you declare a union and put both structures in it like this:

union foobar {
struct foo foo;
struct bar bar;
} u;

? Then you can use u.foo as a struct foo and u.bar as the same data
interpreted as a struct bar.

Technically, isn't it UB to store in one union member and then read
from another?

The only problem is when one of the value you get is a trap and that
won't happen if the structures have the same layout (and it won't happen
if there are not trap reps regardless of layout).

A useful clarification is footnote to 6.5.2.3 p3:

If the member used to access the contents of a union object is not the
same as the member last used to store a value in the object, the
appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as described
in 6.2.6 (a process sometimes called "type punning"). This might be a
trap representation.
Does the Standard say anything about union members
which are identical and/or compatible? (ie: what about "int" and
"long" members, where both are stored identically?)

If "stored identically" means (as it probably must) that they will be
aligned that same and that corresponding bits have the same meanings,
then you'll get the same value out of the long that you put into the
int.
 
D

DSF

{snip}

Can you declare a union and put both structures in it like this:

union foobar {
struct foo foo;
struct bar bar;
} u;

? Then you can use u.foo as a struct foo and u.bar as the same data
interpreted as a struct bar.

This works perfectly! Thanks!

DSF
 
D

DSF

It might be helpful to have some more information about the actual
structures. (I presume they aren't really called "foo" and "bar".)

You've shown us two struct types with exactly the same members
(same member names and types). Do these two libraries really
declare identical types? Are they certain to remain identical in
future versions of both libraries? Is the layout of both structures
imposed by some external interface? See below.

Why does it make sense to pass a "bar" variable to a function in the
"foo" library? Ditto.


"Data, data, data! I cannot make bricks without clay!"

What I posted above is not the exact situation, it's a watered-down
example.

Here is the full story.

The reason I did not post the actual structure data is that there
are a host (as in large number) of sacred cows in this group one must
not go around tipping, and there is a host (as in army) of people
ready to textually rip you a new one if you tip a cow or two. :eek:)

The supine bovine here is that the answer I was looking for need not
be portable, so I decided to use a generic example. In reality, the
first "library" is actually part of Windows and the second is my own.

The Windows "struct" is defined as:
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;

DWORD = unsigned long.
LONG = long.
LONGLONG (see below).

Oops. It's a union. The above is from the WINNT.H file. My Windows
API help file defines it as a structure. With a little more checking,
MS's site has this comment:

"The LARGE_INTEGER structure is actually a union. If your compiler has
built-in support for 64-bit integers, use the QuadPart member to store
the 64-bit integer. Otherwise, use the LowPart and HighPart members to
store the 64-bit integer."

To make matters even stranger, the LONGLONG above that defines
QuadPart is a typedef of double on my system. Although it's the same
number of bits as two longs, I don't believe anything other than zero
in both LowPart and HighPart will be represented correctly in
QuadPart. So I just ignore it and use the LowPart and HighPart.


My structure is defined as:
typedef struct tag_int64 {
unsigned long ldw;
unsigned long hdw;
} int64;

You might be asking why I just didn't use MS's LARGE_INTEGER for my
library. The main reason would be that I'd written the library at a
time where I wasn't using any MS API calls that used LARGE_INTEGER.
Another reason was that it just didn't match my style of programming.
I prefer my variable names to be all lower case, and in the case of
structure members, short. Having to deal with something like:

void foo(unsigned long startl, unsigned long starth);
LARGE_INTEGER count;

Then later,
foo(count.u.LowPart, count.u.HighPart);

isn't a good fit for me.

When I realized that I was going to be dealing with a lot of MS API
calls that use LARGE_INTEGER, I started looking for a better solution
than copying the individual members.

Sorry to be so long winded, but that's the whole story.

Ben Bacarisse's suggestion of a union works perfectly. I use:

typedef union tag_li64 {
int64 i64;
LARGE_INTEGER li;
} li64;

li64 count;

and use count.li for the MS API
and count.i64 for mine.

DSF

P.S. Yes, I know that the high 32 bits of LARGE_INTEGER are signed
whilst they are unsigned for int64. It's not a concern for what I'm
doing.
 
D

DSF

As OP said, they are in libraries that are out of his control.
Sometimes you just have to deal with what is. Haven't you ever had to
deal with an interface you didn't like but was frozen?

-David
What he said :eek:) ...well, almost. See my reply to Keith Thompson.

DSF
 
K

Keith Thompson

DSF said:
The reason I did not post the actual structure data is that there
are a host (as in large number) of sacred cows in this group one must
not go around tipping, and there is a host (as in army) of people
ready to textually rip you a new one if you tip a cow or two. :eek:)

The supine bovine here is that the answer I was looking for need not
be portable, so I decided to use a generic example. In reality, the
first "library" is actually part of Windows and the second is my own.

Hmm. That's not something I'd be particularly concerned about if
I were in your position. My own attitude is that C code should
be a portable as possible, but no more so. One of C's greatest
strengths is actually the ability to use it to write *non-portable*
code. I think most people here would be glad to offer non-portable
solutions where necessary -- as long as you don't mind an occasional
reminder that they're non-portable.
The Windows "struct" is defined as:
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;

DWORD = unsigned long.
LONG = long.
LONGLONG (see below).

Oops. It's a union. The above is from the WINNT.H file. My Windows
API help file defines it as a structure. With a little more checking,
MS's site has this comment:

"The LARGE_INTEGER structure is actually a union. If your compiler has
built-in support for 64-bit integers, use the QuadPart member to store
the 64-bit integer. Otherwise, use the LowPart and HighPart members to
store the 64-bit integer."

To make matters even stranger, the LONGLONG above that defines
QuadPart is a typedef of double on my system. Although it's the same
number of bits as two longs, I don't believe anything other than zero
in both LowPart and HighPart will be represented correctly in
QuadPart. So I just ignore it and use the LowPart and HighPart.

So all this stuff is defined by Windows itself? Ok.
My structure is defined as:
typedef struct tag_int64 {
unsigned long ldw;
unsigned long hdw;
} int64;

You might be asking why I just didn't use MS's LARGE_INTEGER for my
library. The main reason would be that I'd written the library at a
time where I wasn't using any MS API calls that used LARGE_INTEGER.
Another reason was that it just didn't match my style of programming.
I prefer my variable names to be all lower case, and in the case of
structure members, short. Having to deal with something like:

void foo(unsigned long startl, unsigned long starth);
LARGE_INTEGER count;

Then later,
foo(count.u.LowPart, count.u.HighPart);

isn't a good fit for me.

And now, I'm sorry to say, you're paying the price. I have my
own very strong feelings about coding style, and the declaration
of LARGE_INTEGER violates several of them -- but if I'm going to
be using interfaces that are defined in terms of it, I'll grit my
teeth and use it.
When I realized that I was going to be dealing with a lot of MS API
calls that use LARGE_INTEGER, I started looking for a better solution
than copying the individual members.

How difficult would to be to change your own code to use
LARGE_INTEGER the way the system defines it? I'm not saying
that's necesarily the best approach, but you might think about it.
(Unless there's other existing code, outside your control, that
depends on "int64" the way your library defines it.)

Of course, since you've already got a working solution, you can
reasonably ignore my advice.
Sorry to be so long winded, but that's the whole story.

Ben Bacarisse's suggestion of a union works perfectly. I use:

typedef union tag_li64 {
int64 i64;
LARGE_INTEGER li;
} li64;

li64 count;

and use count.li for the MS API
and count.i64 for mine.

Yes, that's a reasonable solution.
DSF

P.S. Yes, I know that the high 32 bits of LARGE_INTEGER are signed
whilst they are unsigned for int64. It's not a concern for what I'm
doing.

Right. It depends on several assumptions about integer
representations -- but since it's Windows-specific anyway, that's
not a big problem.

(Unless you want to port Windows to a machine that doesn't satisfy
those assumptions. Windows has actually been ported to systems
other than x86, but I believe they're all little-endian. Of course
that's *way* outside the scope of what you're working on.)

Some might argue that since this is Windows-specific, it's off-topic
and better discussed in, say, comp.os.ms-windows.programmer.win32.
But since you've provided the C declarations of the relevant
Windows-specific types, I'd say it's more about C than about Windows;
similar issues could arise on any OS.
 
J

Jorgen Grahn

Hello,

I have a situation where I have two structures that are identical
except for the names. A simplified example:

struct foo
{
unsigned long a;
unsigned long b;
};

struct bar
{
unsigned long a;
unsigned long b;
};

I don't have the ability to re-designate either of them, as they
each belong to a different library.

So if I need to pass a function in library "foo" a "bar" variable, I
must create a "foo" variable and copy each member from the "bar"
variable to it. This is not my idea of efficiency.

Create a

static inline struct bar foo2bar(struct foo val);

and let the optimizer deal with it. With a bit of luck the foo2bar()
call just melts away into nothing -- as it should.

/Jorgen
 
D

DSF

Create a

static inline struct bar foo2bar(struct foo val);

and let the optimizer deal with it. With a bit of luck the foo2bar()
call just melts away into nothing -- as it should.

/Jorgen

I have it working, but in the pursuit of knowledge I want to know if
I understand what you're saying. The actual function would be:

static inline struct bar foo2bar(struct foo val)
{
struct bar r;
r.a = val.a;
r.b = val.b;
return r;
}

I then use foo2bar wherever I have a "foo" and a "bar" is needed?

If this is the case, this would cut down on typing, but still
produces more code than I'd like. There wouldn't be a function call,
but the "copy val to r" code would still be created for each "call".

Second problem:

The above prototype and function compile fine as C++, but produce
syntax errors unless "inline" is removed.

DSF
 
D

DSF

Hmm. That's not something I'd be particularly concerned about if
I were in your position. My own attitude is that C code should
be a portable as possible, but no more so. One of C's greatest
strengths is actually the ability to use it to write *non-portable*
code. I think most people here would be glad to offer non-portable
solutions where necessary -- as long as you don't mind an occasional
reminder that they're non-portable.

You're right. This group mellowed a lot in recent years. I have
messages going back to 2003 and it was quite different back then (as
you well know, you were there.) There was a lot of good advice to be
found, but a great deal of it was offered with such snarkiness as to
turn many people off. Some didn't even bother with advice and just
cut to the snarkiness with one line "comments" like "wrong," "not C,"
"not standard - delete it," and other gems. Please note that I don't
include you in the snarky group. Your reply to one of the terse "not
C" comments back in 2006 was refreshingly "unsnarky."

I never understood the overwhelming desire that example code be
entirely standard-based: There is a comp.std.c group for that. (True,
that makes it easier for many to compile and test for themselves, but
quite often errors are glaringly obvious.) My feeling has always been
that if a question is based on the features of a particular compiler
or operating system, it is off topic. If the question involves the C
language, example code that includes OS specific calls or compiler
specific code should not make the question off topic.

And now, I'm sorry to say, you're paying the price. I have my
own very strong feelings about coding style, and the declaration
of LARGE_INTEGER violates several of them -- but if I'm going to
be using interfaces that are defined in terms of it, I'll grit my
teeth and use it.

How difficult would to be to change your own code to use
LARGE_INTEGER the way the system defines it? I'm not saying
that's necesarily the best approach, but you might think about it.
(Unless there's other existing code, outside your control, that
depends on "int64" the way your library defines it.)

It's not a very big price. I could change my library to use
LARGE_INTEGER very easily. It would only require changing the header
file, but I'm going to stick with the union method. Big reason is
that the int64 library exists solely because my compiler doesn't have
a 64 bit type. As soon as I find a newer compiler I am happy with,
I'll most likely not need the library anymore.

Some might argue that since this is Windows-specific, it's off-topic
and better discussed in, say, comp.os.ms-windows.programmer.win32.
But since you've provided the C declarations of the relevant
Windows-specific types, I'd say it's more about C than about Windows;
similar issues could arise on any OS.

Thank you.

DSF
 
S

Seebs

I never understood the overwhelming desire that example code be
entirely standard-based: There is a comp.std.c group for that.

No, there is a comp.std.c group for discussing the standard *itself*,
not for discussing code conforming with the standard.

Think of it like legislation. If you want to discuss running a small
business, you might conclude that your forum is better served if you
agree to all discuss *legal* small businesses. Responding that the
legislature already exists for discussing laws governing small businesses
does not really address that.
(True,
that makes it easier for many to compile and test for themselves, but
quite often errors are glaringly obvious.) My feeling has always been
that if a question is based on the features of a particular compiler
or operating system, it is off topic. If the question involves the C
language, example code that includes OS specific calls or compiler
specific code should not make the question off topic.

I mostly agree. The problem is that in some cases, you have to know a fair
bit about a platform to know whether something is an error or not.

Consider the UNIX faq:

if (fd = open("foo", O_RDWR) != -1) {
write(fd, "hello!\n", 7);
}

Why does this print hello instead of writing it to a file?

It turns out that you can't easily answer this if you don't know a
fair bit about Unix, but you don't need to know anything about Unix
to guess at the problem.

Basically... I figure people are justified in not trying to answer such
questions, or suggesting that you'll get a better answer in a
platform-specific group. But I also try to answer them when I notice
a generic-C answer.

-s
 
J

James Kuyper

On 04/07/2011 10:57 PM, DSF wrote:
....
I never understood the overwhelming desire that example code be
entirely standard-based: There is a comp.std.c group for that.

Not true; comp.std.c is for discussing the C standard; it's not for
discussing how to write C code (except insofar as there's an issue about
what the standard says about the code in question).
or operating system, it is off topic. If the question involves the C
language, example code that includes OS specific calls or compiler
specific code should not make the question off topic.

There are OS-specific and compiler-specific forums where such questions
will be answered in a more reliably accurate fashion.
 
B

Ben Bacarisse

DSF said:
I have it working, but in the pursuit of knowledge I want to know if
I understand what you're saying. The actual function would be:

static inline struct bar foo2bar(struct foo val)
{
struct bar r;
r.a = val.a;
r.b = val.b;
return r;
}

or you could use a C99 compound literal making the function body simply

return (struct bar){val.a, val.b};
I then use foo2bar wherever I have a "foo" and a "bar" is needed?

Not quite. Function calls are not "lvalues" which means (in part) that
you can't take the address of the result. So if you need a bar in some
context where it's address gets taken, you can use the function call.
If this is the case, this would cut down on typing, but still
produces more code than I'd like. There wouldn't be a function call,
but the "copy val to r" code would still be created for each "call".

I'd have though that depends on the context and the quality of the
optimiser but there may be some reason I can't see why it is hard to
remove r altogether.
Second problem:

The above prototype and function compile fine as C++, but produce
syntax errors unless "inline" is removed.

Have you been addressing a C++ problem all along or are you trying to
write this code in a language that is the intersection of valid C and
valid C++? If so, I am curious about why you need to have this extra
headache.
 
B

Ben Bacarisse

James Kuyper said:
On 04/07/2011 10:57 PM, DSF wrote:

There are OS-specific and compiler-specific forums where such
questions will be answered in a more reliably accurate fashion.

Did you miss the "if the question involves the C language" part? I
suspect that C questions will be more accurately answered here than in
some system-specific group.

You might argue that a question that involves C is not necessarily a
question about C, but then what is the point of the second part of the
OP's sentence? It seems to me that the OP is talking about C questions
that just happen to be illustrated with system-specific code.
 
J

James Kuyper

Did you miss the "if the question involves the C language" part? I
suspect that C questions will be more accurately answered here than in
some system-specific group.

You might argue that a question that involves C is not necessarily a
question about C,

Yes, that's precisely my point.
... but then what is the point of the second part of the
OP's sentence? It seems to me that the OP is talking about C questions
that just happen to be illustrated with system-specific code.

As a general rule, if a question does not involve OS- or
compiler-specific issues, the code can always be rewritten to make no
use of or reference to anything involving that particular OS or
compiler, while retaining the issue you wish to discuss. Such a re-write
should be performed before posting it here.

Should such a re-write turn out to be impossible, then that very
impossibility indicates that the question should be posted to an OS- or
compiler-specific forum, in order to get a more useful answer.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top