Valid C++?

  • Thread starter andrew queisser
  • Start date
A

andrew queisser

Is this code below valid C++? I'd like to use this construct but I'm not
sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};



Thanks,
Andrew
 
N

Noah Roberts

andrew said:
Is this code below valid C++? I'd like to use this construct but I'm not
sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};

Yes it is valid. However, I believe it also results in undefined
behavior.

On the other hand, it is a common technique to use especially in C, for
instance:

diff = (&((foo*)0)->x - ((foo*)0))

or something similar.

Most compilers create code that does what you expect here. Since you
are not reading from x or writing to it its just arith operations on a
pointer variable.
 
M

mlimber

andrew said:
Is this code below valid C++? I'd like to use this construct but I'm not
sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};

Though that seems to work, for the sake of clarity, I would do it
differently. At worst, something like this:

char sameSizeAsFooX[ sizeof foo().x ];

Better, IMHO, would be:

struct foo
{
enum { SIZE = 128 };
char x[SIZE];
};

struct bar
{
char sameSizeAsFooX[ foo::SIZE ];
};

Cheers! --M
 
V

Victor Bazarov

andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];

It is OK, I guess. Seems rather dangerous though, like dereferencing
a null pointer. Perhaps it would be less scary to do

char sameSizeAsFoox[ sizeof foo().x ];

(although it does require for 'foo' to be default-constructible while
your solution does not).

V
 
V

Victor Bazarov

Noah said:
andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};

Yes it is valid. However, I believe it also results in undefined
behavior.

It does not. The dereferencing behind the -> is never evaluated.

V
 
V

Victor Bazarov

mlimber said:
andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};

Though that seems to work, for the sake of clarity, I would do it
differently. At worst, something like this:

char sameSizeAsFooX[ sizeof foo().x ];

This requires 'foo' to be default-constructible, which is not always
possible.
Better, IMHO, would be:

struct foo
{
enum { SIZE = 128 };
char x[SIZE];
};

struct bar
{
char sameSizeAsFooX[ foo::SIZE ];
};

I agree. The problem is that editing 'foo' to introduce 'SIZE' is not
always possible. Besides, the trick with (0)-> can be used in templates
whereas you cannot expect every class that has 'x' member for which you
want to create a corresponding 'sameSizeAs..' also contains 'SIZE'...

V
 
A

Alf P. Steinbach

* Victor Bazarov:
andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];

It is OK, I guess. Seems rather dangerous though, like dereferencing
a null pointer. Perhaps it would be less scary to do

char sameSizeAsFoox[ sizeof foo().x ];

(although it does require for 'foo' to be default-constructible while
your solution does not).

On the one hand, dereferencing a null-pointer is formally UB no matter
which context (except in a typeid expression).

On the other hand, the only harm it can do inside a sizeof is to make
som rather dumb compiler choke on the expression, and it's an old idiom.

On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];
 
N

Noah Roberts

Alf said:
On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

Does that remove UB?
 
V

Victor Bazarov

Alf said:
* Victor Bazarov:
andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];

It is OK, I guess. Seems rather dangerous though, like dereferencing
a null pointer. Perhaps it would be less scary to do

char sameSizeAsFoox[ sizeof foo().x ];

(although it does require for 'foo' to be default-constructible while
your solution does not).

On the one hand, dereferencing a null-pointer is formally UB no matter
which context (except in a typeid expression).

According to 3.2/2 the full expression ((foo*)0)->x is not evaluated.
'sizeof' has the same standing as 'typeid' in this matter, AFAICT.
[..a nice trick with UFF redacted..]

V
 
R

Rolf Magnus

Alf said:
* Victor Bazarov:
andrew said:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];

It is OK, I guess. Seems rather dangerous though, like dereferencing
a null pointer. Perhaps it would be less scary to do

char sameSizeAsFoox[ sizeof foo().x ];

(although it does require for 'foo' to be default-constructible while
your solution does not).

On the one hand, dereferencing a null-pointer is formally UB no matter
which context (except in a typeid expression).

Actually, the exception covers not only typeid, but also sizeof:

"An expression is potentially evaluated unless either it is the operand of
the sizeof operator (5.3.3), or it is the operand of the typeid operator
and does not designate an lvalue of polymorphic class type (5.2.8)."
 
V

Victor Bazarov

Noah said:
Alf said:
On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

Does that remove UB?

It cannot remove what does not exist. Further, it creates a violation
of the ODR, if 'sizeof' expression *were* evaluated. If 'sizeof' is not
evaluated (and it isn't, see 3.2/2), then neither is a violation.

V
 
N

Noah Roberts

Noah said:
Alf said:
On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

This doesn't work if you're trying to implement an offset function.
 
?

=?ISO-8859-1?Q?Sch=FCle_Daniel?=

andrew said:
Is this code below valid C++? I'd like to use this construct but I'm not
sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
};



Thanks,
Andrew

struct foo {
char x[128];
};

union bar {
struct foo dummy;
char * sameSizeAsFoo;
};

maybe that helps

Regards, Daniel
 
V

Victor Bazarov

Noah said:
Noah said:
Alf said:
On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

This doesn't work if you're trying to implement an offset function.

What's "an offset function"?

V
 
N

Noah Roberts

Victor said:
Noah said:
Noah said:
Alf P. Steinbach wrote:

On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

This doesn't work if you're trying to implement an offset function.

What's "an offset function"?

A function that calculates the offset of a member of course.
 
A

Andre Kostur

Victor said:
Noah said:
Noah Roberts wrote:
Alf P. Steinbach wrote:

On the third & gripping hand, at the technical level, where we don't
care about how a better design might make the need go away, this is
really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

This doesn't work if you're trying to implement an offset function.

What's "an offset function"?

A function that calculates the offset of a member of course.

Like offsetof() ?
 
V

Victor Bazarov

Noah said:
Victor said:
Noah said:
Noah Roberts wrote:
Alf P. Steinbach wrote:

On the third & gripping hand, at the technical level, where we
don't care about how a better design might make the need go away,
this is really a job for the Unimplemented Fake Function, the UFF,

foo& foon();

char samesizeAsFoox[ sizeof( foon().x ) ];

Heh, cute. Never seen that done before.

This doesn't work if you're trying to implement an offset function.

What's "an offset function"?

A function that calculates the offset of a member of course.

Ah... OK. What would be the purpose of it? I don't think I ever had
a need in a function like that, and that's why I'm asking. Thanks!

V
 
A

Alf P. Steinbach

* Rolf Magnus:
Alf said:
* Victor Bazarov:
andrew queisser wrote:
Is this code below valid C++? I'd like to use this construct but I'm
not sure if it'll be portable.

struct foo
{
char x[128];
};
struct bar
{
char sameSizeAsFooX[ sizeof ((foo *)0)->x ];
It is OK, I guess. Seems rather dangerous though, like dereferencing
a null pointer. Perhaps it would be less scary to do

char sameSizeAsFoox[ sizeof foo().x ];

(although it does require for 'foo' to be default-constructible while
your solution does not).

};
On the one hand, dereferencing a null-pointer is formally UB no matter
which context (except in a typeid expression).

Actually, the exception covers not only typeid, but also sizeof:

"An expression is potentially evaluated unless either it is the operand of
the sizeof operator (5.3.3), or it is the operand of the typeid operator
and does not designate an lvalue of polymorphic class type (5.2.8)."

No, that isn't the exception that applies to typeid.

And no, it doesn't matter whether a dereferencing is potentially
evaluated or not.
 
N

Noah Roberts

Andre said:
Like offsetof() ?

yes, exactly like that.

usual definition something like so:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

As to the question of usefulness - not very. Not in C++ anyway.
 
B

Bo Persson

Noah Roberts said:
yes, exactly like that.

usual definition something like so:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

As to the question of usefulness - not very. Not in C++ anyway.

And that isn't really valid C++ anyway.

It is only *if* the compiler implementor cares to define the behavior
for the offsetof macro, that this works. Otherwise not.

An equally common definition is

#define offsetof(_Structure, _Member)
__builtin_offsetof(_Structure, _Member)

where the compiler people (gcc) have chosen to support another trick.


Bo Persson
 

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,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top