• Create Account

#ActualHodgman

Posted 04 January 2013 - 01:45 AM

You also should read this site, which matters if there are virtual tables.

Yeah, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

I've read that before and the MS explanation for their extra padding is interesting though ;)

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

Bregma already said this wasn't true, but the C99 wording seems to say that a particular group of bytes (an object) takes on an effective type when it's written to, and then that written value can be fetched by basically any expression with a compatible type, which includes aggregates that are made up of compatible types. They key is that it says that the type of the lvalue expression is an aggregate, not that the type is a compatible member of an aggregate.

It does make sense that the point of this statement is so that I can write to a.value, and then make a copy of 'a' as a whole (which needs to read a.value)... but it seems ambiguous enough that it also allows for reading ((B*)&a)->value too

#5Hodgman

Posted 04 January 2013 - 01:45 AM

You also should read this site, which matters if there are virtual tables.

Yeah, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

I've read that before and the MS explanation for their extra padding is interesting though ;)

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

Bregma already said this wasn't true, but the C99 wording seems to say that a particular group of bytes (an object) takes on an effective type when it's written to, and then that written value can be fetched by basically any expression with a compatible type, which includes aggregates that are made up of compatible types. They key is that it says that the type of the lvalue expression is an aggregate, not that the type is a compatible member of an aggregate.

It does make sense that the point of this statement is so that I can write to a.value, and then make a copy of 'a' as a whole (which needs to read a.value)... but it seems ambiguous enough that it also allows for reading ((B*)&a)->value too

#4Hodgman

Posted 04 January 2013 - 12:37 AM

You also should read this site, which matters if there are virtual tables.

Yeah, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

I've read that before and the MS explanation for their extra padding is interesting though ;)

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

Bregma already said this wasn't true, but the C99 wording seems to say that a particular group of bytes (an object) takes on an effective type when it's written to, and then that written value can be fetched by basically any expression with a compatible type, which includes aggregates that are made up of compatible types. They key is that it says that the type of the lvalue expression is an aggregate, not that the type is a compatible member of an aggregate.

#3Hodgman

Posted 04 January 2013 - 12:30 AM

You also should read this site, which matters if there are virtual tables.

Yeah, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

I've read that before and the MS explanation for their extra padding is interesting though ;)

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

Bregma already said this wasn't true, but the C99 wording seems to say that a particular group of bytes (an object) takes on an effective type when it's written to, and then that written value can be fetched by basically any expression with a compatible type, which includes aggregates that are made up of compatible types.

#2Hodgman

Posted 03 January 2013 - 11:52 PM

You also should read this site, which matters if there are virtual tables.

Yeah, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

I've read that before and the MS explanation for their extra padding is interesting though ;)

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

#1Hodgman

Posted 03 January 2013 - 11:44 PM

You also should read this site, which matters if there are virtual tables.

Yes, I'm only interested in C++ POD types, and C types. The details of C++ non-POD types are obviously a lot more unpredictable across platforms.

Strictly speaking, no; because Foo & Command weren't supposed to point to the same memory location in the first place.

Switching over to C99 lingo for a moment, it's possible to have an allocation that doesn't have a type:

void* data = malloc(sizeof(int));

and it only takes on the effective type of int when you store a value in it, and it maintains this effective type until it's next written to:

(*(int*)data)  = 42;

after the above line, it's undefined to access it via another type:

float f = *(float*)data;//undefined

however, as the (C99 version of the) rules in my first post say, it's valid to access the stored value via an lvalue expression that has the type of an aggregate type that includes an integer member...

So even though the allocation never had the effective type of this aggregate, the effective type is compatible with the member of the aggregate (and the object-type, aka byte-representation of both are equal too), so it sounds like this should be valid:

struct A { int value; };
A a = *(A*)data;

In which case, I could have an A and a B legitimately reading from the same memory address?

PARTNERS