Discussion:
"deriving" parent from child structs...
(too old to reply)
Chris M. Thomasson
2017-07-25 06:27:04 UTC
Permalink
Raw Message
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
in another thread:
_______________________
#include <stdio.h>

struct ct_parent
{
int parent_a;
};

struct ct_child
{
struct ct_parent parent;
int child_a;
};


/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?

printf("parent:%p, parent_a:%d\n", (void*)parent, parent->parent_a);
printf("child:%p, child:%d\n", (void*)&child, child.child_a);

return 0;
}
_______________________


The order is important here. If I move parent in child, well, offsetof
needs to be used.
luser droog
2017-07-25 15:39:08 UTC
Permalink
Raw Message
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
You can avoid the whole issue (and the cast) by using

&child.parent //already the correct type

instead of

(struct ct_parent*)&child

.
Post by Chris M. Thomasson
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
printf("parent:%p, parent_a:%d\n", (void*)parent, parent->parent_a);
printf("child:%p, child:%d\n", (void*)&child, child.child_a);
return 0;
}
_______________________
The order is important here. If I move parent in child, well, offsetof
needs to be used.
b***@gmail.com
2017-07-25 15:52:10 UTC
Permalink
Raw Message
The only difference I'd do, is have the the parent in the child (your wording is backwards btw) be a pointer to it.

so something like

`struct ct_child {
struct ct_parent *Parent;
}`
James R. Kuyper
2017-07-25 16:24:34 UTC
Permalink
Raw Message
Post by b***@gmail.com
The only difference I'd do, is have the the parent in the child (your wording is backwards btw) be a pointer to it.
so something like
`struct ct_child {
struct ct_parent *Parent;
}`
That would be appropriate if one parent object has many corresponding
child objects. However, since he's talking about writing the C
equivalent of C++ class derivation, struct ct_parent is a parent type,
with multiple child types that might be derived from. However, in C++,
each distinct instance of a derived type also contains a distinct
instance of it's base class, so dealing with the same issue in C by
including it as a member rather than a pointer is entirely appropriate.
James R. Kuyper
2017-07-25 16:01:57 UTC
Permalink
Raw Message
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".

...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
Chris M. Thomasson
2017-07-25 18:32:09 UTC
Permalink
Raw Message
Post by James R. Kuyper
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".
...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
For some reason, I brought this up as a response to Jerry. The main
issue was the cast itself, not the ideal way of simply using &child->parent.
James R. Kuyper
2017-07-25 19:06:50 UTC
Permalink
Raw Message
Post by Chris M. Thomasson
Post by James R. Kuyper
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".
...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
For some reason, I brought this up as a response to Jerry. The main
issue was the cast itself, not the ideal way of simply using &child->parent.
Given that Jerry seems to be unaware of 6.7.2.1p15, I can't fault him
for rejecting your unsupported assertion that this code is guaranteed to
be safe. Naively, it might seem reasonable that any such statement would
be found in the 6.3.2.3, the clause covering pointer conversions in
general, but the committee chose to place it in the section describing
struct declarations instead.
Jerry Stuckle
2017-07-25 19:37:07 UTC
Permalink
Raw Message
Post by James R. Kuyper
Post by Chris M. Thomasson
Post by James R. Kuyper
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".
...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
For some reason, I brought this up as a response to Jerry. The main
issue was the cast itself, not the ideal way of simply using
&child->parent.
Given that Jerry seems to be unaware of 6.7.2.1p15, I can't fault him
for rejecting your unsupported assertion that this code is guaranteed to
be safe. Naively, it might seem reasonable that any such statement would
be found in the 6.3.2.3, the clause covering pointer conversions in
general, but the committee chose to place it in the section describing
struct declarations instead.
You should be following the thread before making a fool of yourself,
James. I quoted 6.7.2 in my claim.

The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
j***@verizon.net
2017-07-25 19:49:49 UTC
Permalink
Raw Message
Post by Jerry Stuckle
Post by James R. Kuyper
Post by Chris M. Thomasson
Post by James R. Kuyper
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".
...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
For some reason, I brought this up as a response to Jerry. The main
issue was the cast itself, not the ideal way of simply using &child->parent.
Given that Jerry seems to be unaware of 6.7.2.1p15, I can't fault him
for rejecting your unsupported assertion that this code is guaranteed to
be safe. Naively, it might seem reasonable that any such statement would
be found in the 6.3.2.3, the clause covering pointer conversions in
general, but the committee chose to place it in the section describing
struct declarations instead.
You should be following the thread before making a fool of yourself,
James. I quoted 6.7.2 in my claim.
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the only time 6.7.2.1p15 could possibly apply would be if the initial member of a struct had the same type as the struct itself. But that's expressly prohibited: "... a structure shall not contain an instance of itself ..." (6.7.2.1p3), for what I hope are perfectly obvious reasons.

Can you show me an example of a "suitably converted" "pointer to a structure object" that does point "to its initial member"? If not, what is your understanding of why the standard bothers talking about a situation that could never come up?
Richard Heathfield
2017-07-25 19:58:56 UTC
Permalink
Raw Message
On 25/07/17 20:49, ***@verizon.net wrote:

<snip>
Post by j***@verizon.net
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"?
Yes. All of them. Are you missing a "not"?
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
James R. Kuyper
2017-07-25 20:54:00 UTC
Permalink
Raw Message
Post by Richard Heathfield
<snip>
Post by j***@verizon.net
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"?
Yes. All of them. Are you missing a "not"?
No, I'm referring to Jerry's misinterpretation of "suitably converted",
which requires that the structure and the initial member of the
structure must both have compatible types. In this context, compatible
types basically means "the same type", That implies infinite recursion,
which is not necessarily a problem so long as the only member of the
struct is the first one - except that such a struct would be completely
useless. If there were any other members of such struct, then there
would have to be infinitely many of them - if the following declaration
were permitted:

struct a { struct a a; int b; } c;

then c.b, c.a.b, c.a.a.b, etc. would all have to exist and be distinct
from each other. That's why the standard expressly forbids a struct from
containing a member of its own type.

Therefore, if his interpretation of "suitably converted" were correct,
it would be impossible for any such pointer to be suitably converted.
Technically, that would be consistent with your answer, "All of them",
since it would make "All of them" an empty set. I'm inviting him to
prove me that there is some context in which the pointer can be
"suitably converted", as he mis-interprets that term.

If there were indeed no such cases, then the committee would have been
wasting their time writing about a case that can never come up.
I don't think they were wasting their time. I think that by "suitably
converted" they mean "converted by application of a cast operator
specifying a pointer to the type of that member".

He correctly cited 6.2.7 to justify his correct claim that struct
ct_parent and struct ct_child were incompatible types. He neglected to
justify his claim that they had to be compatible types in order for the
conversion to work. The applicable clause, 6.3.2.3p3, imposes no such
requirement. Since 6.7.2.1p15 guarantees that the pointer points at the
initial member, it's guaranteed to be correctly aligned, so that's not a
problem. Since the initial member has an effective type that exactly
matches the type that the converted pointer points at, the anti-aliasing
rules (6.5p7) aren't violated, either.
Richard Heathfield
2017-07-25 21:09:45 UTC
Permalink
Raw Message
Post by Richard Heathfield
<snip>
Post by j***@verizon.net
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"?
Yes. All of them. Are you missing a "not"?
No
Thank you for clearing that up.

<actual clearing-up snipped>
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Jerry Stuckle
2017-07-26 03:19:43 UTC
Permalink
Raw Message
Post by j***@verizon.net
Post by Jerry Stuckle
Post by James R. Kuyper
Post by Chris M. Thomasson
Post by James R. Kuyper
Post by Chris M. Thomasson
Wrt using/exploiting the first member of a struct, Jerry Stuckle, seems
to think that the following is not standard. Is he correct? I think this
should work like a charm. I ask this because the question is buried down
_______________________
#include <stdio.h>
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
/* Testing 123...
__________________________________________________*/
int main(void)
{
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
I haven't been following that thread, but I just did a Google Groups
search, and it doesn't appear that anyone has bothered citing 6.7.2.1p15
to him yet. "A pointer to a structure object, suitably converted, points
to its initial member ...".
...
Post by Chris M. Thomasson
The order is important here. If I move parent in child, well, offsetof
needs to be used.
Why? Using the expression &child->parent would be much simpler than any
corresponding use of offsetof().
For some reason, I brought this up as a response to Jerry. The main
issue was the cast itself, not the ideal way of simply using &child->parent.
Given that Jerry seems to be unaware of 6.7.2.1p15, I can't fault him
for rejecting your unsupported assertion that this code is guaranteed to
be safe. Naively, it might seem reasonable that any such statement would
be found in the 6.3.2.3, the clause covering pointer conversions in
general, but the committee chose to place it in the section describing
struct declarations instead.
g
You should be following the thread before making a fool of yourself,
James. I quoted 6.7.2 in my claim.
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the only time 6.7.2.1p15 could possibly apply would be if the initial member of a struct had the same type as the struct itself. But that's expressly prohibited: "... a structure shall not contain an instance of itself ..." (6.7.2.1p3), for what I hope are perfectly obvious reasons.
Can you show me an example of a "suitably converted" "pointer to a structure object" that does point "to its initial member"? If not, what is your understanding of why the standard bothers talking about a situation that could never come up?
Sorry, finger c heck on my part. The applicable paragraph is 6.2.7 p1,
not 6.7.2.1p15. It says in part:

"Moreover, two structure, union, or enumerated types declared in
separate translation units are compatible if their tags and members
satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are completed
anywhere within their respective translation units, then the following
additional requirements apply: there shall be a one-to-one
correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values. "

According to this, the two structures are not compatible (but I also
said it would probably work with most compilers nowadays).
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
j***@verizon.net
2017-07-26 16:19:49 UTC
Permalink
Raw Message
...
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the
only time 6.7.2.1p15 could possibly apply would be if the initial member of
a struct had the same type as the struct itself. But that's expressly
prohibited: "... a structure shall not contain an instance of itself ..."
(6.7.2.1p3), for what I hope are perfectly obvious reasons.
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"? If not, what is
your understanding of why the standard bothers talking about a situation
that could never come up?
Sorry, finger c heck on my part. The applicable paragraph is 6.2.7 p1,
"Moreover, two structure, union, or enumerated types declared in
separate translation units ...
These types are declared in the same translation unit, so that's sufficient to render this sentence inapplicable.
Post by Jerry Stuckle
... are compatible if their tags and members
satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are completed
anywhere within their respective translation units, then the following
additional requirements apply: there shall be a one-to-one
correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values. "
There's no need to go into all of those details for types declared in the same
translation unit. If declared in the same translation unit, even two different
struct types that meet all of those requirements would be incompatible with
each other.
Post by Jerry Stuckle
According to this, the two structures are not compatible ...
That's true, but not for the reason you seem to think - they're incompatible
simply because none of the rules that say two types are compatible apply to
these types. The part you quoted from 6.2.7p1 doesn't apply simply because they
are declared in the same translation unit.

No one has ever disagreed with you about struct ct_child being incompatible
with struct ct_parent. I pointed that out to you in the same message you
responded to. So, what? There's no applicable requirement that they be
compatible.
Post by Jerry Stuckle
... (but I also
said it would probably work with most compilers nowadays).
It's required to work on any compiler conforming to any version of the C
standard. For that matter, it's also required to work for the first non-static
data member of a layout-compatible class in C++ (9.2p19, C++2011).

From past experience with you, I expect that any reply you make to this message
will be non-responsive. Just to make it clearer that you're failing to be
responsive, I'm going to number the following questions, and for each question,
identify what would constitute a responsive answer to the question.

I'm going to cite this here, because the citation near the top of the message
was getting so heavily indented as to be unreadable:

On Tuesday, July 25, 2017 at 2:27:23 AM UTC-4, Chris M. Thomasson wrote:
..
Post by Jerry Stuckle
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
...
Post by Jerry Stuckle
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
1. What requirement of the C standard do you think is violated by the code
above, due to the universally acknowledged fact that struct ct_parent is not
compatible with struct ct_child?
A responsive answer will at least identify the precise paragraph in the
standard which imposes such a requirement, and preferably would quote the text
expressing that requirement.

2. If you were right about "suitably converted" requiring that the types be
compatible, then since the struct ct_child is a struct type, such a pointer
could be "suitably converted" only if it's initial member has the same type as
the struct itself. Do you agree?
Responsive answers will either say "Yes" or "No", or provide an explanation why
neither of those two answers is appropriate. I'll abbreviate this as Y/N/O
further down.

3. The standard prohibits a struct type from containing a member of the same
type (6.7.2.1p3). Do you agree?
Responsive answers will be Y/N/O.

4. If you answered "Yes" to questions 2 and 3, and if you were correct that the
types had to be compatible in order for the conversion to be "suitable", it
would therefore be impossible, in strictly conforming code, for the conversion
to ever be suitable? Do you agree?
Responsive answers will be Y/N/O.

5. If you answered "Yes" to question 4, then what do you think was the reason
why the committee wasted time writing 6.7.2.1p15, to describe a situation that
could never come up?
A responsive answer will actually identify a reason.

6. If you answered anything other than "Yes" to question 4, please provide an
example of code that meets your understanding of the requirements for "suitably
converted", as that phrase is used in 6.7.2.1p15.
A responsive answer will provide source code that includes a declaration of a
struct type, and a conversion of a pointer to the struct type into a pointer to
the type of it's first member. It will also conform to the requirement that you
believe exists, in order for that conversion to have defined behavior - namely,
that those two types be compatible. It will also not violate 6.7.2.1p3. Good
luck!
s***@casperkitty.com
2017-07-26 16:56:13 UTC
Permalink
Raw Message
Post by j***@verizon.net
There's no need to go into all of those details for types declared in the same
translation unit. If declared in the same translation unit, even two different
struct types that meet all of those requirements would be incompatible with
each other.
If types are compatible, pointers to them may be implicitly converted
without the need for explicit casts nor conversions through void*.

The purpose of the cited text with regard to structs, and the following
paragraph about unions, is to suggest that pointers to some types which
are cast to other incompatible types may be usefully employed to access
things of those latter types.

Unfortunately, C99 got a bit muddy with respect to the relationship between
union member objects and pointers to them. C89 makes no promise in the
general case about the effect of writing one member (whether directly or
via pointer) and reading another (likewise), beyond saying that it is
Implementation-Defined. It also makes no distinction between the behaviors
of direct and indirect accesses, but would allow implementations to make
stronger or weaker behavioral promises based on such criteria. I don't
see anything in C99 that would distinguish direct and indirect accesses to
union members; C99 adds more specific behavioral promises that apply in
some situations, but so far as I can tell fails to specify what those
situations are and--unlike C89--doesn't require that implementations document
them either.
James Kuyper
2017-07-27 00:02:41 UTC
Permalink
Raw Message
On 07/26/2017 12:19 PM, ***@verizon.net wrote:
...
Post by j***@verizon.net
It's required to work on any compiler conforming to any version of the C
standard. For that matter, it's also required to work for the first non-static
data member of a layout-compatible class in C++ (9.2p19, C++2011).
That should have been "standard layout" rather than "layout-compatible".
I'm not as familiar with C++ jargon as I am with C jargon, or I would
have noticed that error before I posted it.
Jerry Stuckle
2017-07-27 02:20:13 UTC
Permalink
Raw Message
Post by j***@verizon.net
...
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the
only time 6.7.2.1p15 could possibly apply would be if the initial member of
a struct had the same type as the struct itself. But that's expressly
prohibited: "... a structure shall not contain an instance of itself ..."
(6.7.2.1p3), for what I hope are perfectly obvious reasons.
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"? If not, what is
your understanding of why the standard bothers talking about a situation
that could never come up?
Sorry, finger c heck on my part. The applicable paragraph is 6.2.7 p1,
"Moreover, two structure, union, or enumerated types declared in
separate translation units ...
These types are declared in the same translation unit, so that's sufficient to render this sentence inapplicable.
Even if they're in the same translation unit, it makes no difference.
They are still not compatible.
Post by j***@verizon.net
Post by Jerry Stuckle
... are compatible if their tags and members
satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are completed
anywhere within their respective translation units, then the following
additional requirements apply: there shall be a one-to-one
correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values. "
There's no need to go into all of those details for types declared in the same
translation unit. If declared in the same translation unit, even two different
struct types that meet all of those requirements would be incompatible with
each other.
Just the fact they are defined in the same translation unit does not
mean they are compatible.
Post by j***@verizon.net
Post by Jerry Stuckle
According to this, the two structures are not compatible ...
That's true, but not for the reason you seem to think - they're incompatible
simply because none of the rules that say two types are compatible apply to
these types. The part you quoted from 6.2.7p1 doesn't apply simply because they
are declared in the same translation unit.
They still aren't compatible. What this refers to is the fact if they
are defined in a separate translation unit, the conditions under which
they are compatible. It does not mean if they are defined in the same
translation unit that they are compatible.
Post by j***@verizon.net
No one has ever disagreed with you about struct ct_child being incompatible
with struct ct_parent. I pointed that out to you in the same message you
responded to. So, what? There's no applicable requirement that they be
compatible.
But that is the specific question Chris asked.
Post by j***@verizon.net
Post by Jerry Stuckle
... (but I also
said it would probably work with most compilers nowadays).
It's required to work on any compiler conforming to any version of the C
standard. For that matter, it's also required to work for the first non-static
data member of a layout-compatible class in C++ (9.2p19, C++2011).
If they are compatible. But they are not compatible because they have
different definitions.
Post by j***@verizon.net
From past experience with you, I expect that any reply you make to this message
will be non-responsive. Just to make it clearer that you're failing to be
responsive, I'm going to number the following questions, and for each question,
identify what would constitute a responsive answer to the question.
I respond. And I don't agree with you. Show me where the standard says
the two are compatible.
Post by j***@verizon.net
I'm going to cite this here, because the citation near the top of the message
..
Post by Jerry Stuckle
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
...
Post by Jerry Stuckle
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
1. What requirement of the C standard do you think is violated by the code
above, due to the universally acknowledged fact that struct ct_parent is not
compatible with struct ct_child?
A responsive answer will at least identify the precise paragraph in the
standard which imposes such a requirement, and preferably would quote the text
expressing that requirement.
They do not have the same definition, and C does not provide a way to
convert one user type to another.
Post by j***@verizon.net
2. If you were right about "suitably converted" requiring that the types be
compatible, then since the struct ct_child is a struct type, such a pointer
could be "suitably converted" only if it's initial member has the same type as
the struct itself. Do you agree?
Responsive answers will either say "Yes" or "No", or provide an explanation why
neither of those two answers is appropriate. I'll abbreviate this as Y/N/O
further down.
You can't convert something to an incompatible type.
Post by j***@verizon.net
3. The standard prohibits a struct type from containing a member of the same
type (6.7.2.1p3). Do you agree?
Responsive answers will be Y/N/O.
The same struct can't have two members of the same name, but two
different structs very well can.
Post by j***@verizon.net
4. If you answered "Yes" to questions 2 and 3, and if you were correct that the
types had to be compatible in order for the conversion to be "suitable", it
would therefore be impossible, in strictly conforming code, for the conversion
to ever be suitable? Do you agree?
Responsive answers will be Y/N/O.
See above.
Post by j***@verizon.net
5. If you answered "Yes" to question 4, then what do you think was the reason
why the committee wasted time writing 6.7.2.1p15, to describe a situation that
could never come up?
A responsive answer will actually identify a reason.
There are other types of pointers, also. But just because a pointer can
be converted to point at a structure does not mean the structures are
compatible. Point me where it says they are.

And why don't you ask the C standards committee why they said this?
Post by j***@verizon.net
6. If you answered anything other than "Yes" to question 4, please provide an
example of code that meets your understanding of the requirements for "suitably
converted", as that phrase is used in 6.7.2.1p15.
A responsive answer will provide source code that includes a declaration of a
struct type, and a conversion of a pointer to the struct type into a pointer to
the type of it's first member. It will also conform to the requirement that you
believe exists, in order for that conversion to have defined behavior - namely,
that those two types be compatible. It will also not violate 6.7.2.1p3. Good
luck!
Other than two structures defined the same way, I don't know of any way
within the standard to ensure they are compatible. Why don't you ask
the standards committee to provide you with an example?
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
j***@verizon.net
2017-07-27 03:07:17 UTC
Permalink
Raw Message
Post by Jerry Stuckle
Post by j***@verizon.net
...
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the
only time 6.7.2.1p15 could possibly apply would be if the initial member of
a struct had the same type as the struct itself. But that's expressly
prohibited: "... a structure shall not contain an instance of itself ..."
(6.7.2.1p3), for what I hope are perfectly obvious reasons.
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"? If not, what is
your understanding of why the standard bothers talking about a situation
that could never come up?
Sorry, finger c heck on my part. The applicable paragraph is 6.2.7 p1,
"Moreover, two structure, union, or enumerated types declared in
separate translation units ...
These types are declared in the same translation unit, so that's sufficient to render this sentence inapplicable.
Even if they're in the same translation unit, it makes no difference.
They are still not compatible.
Which is what I just said. "This sentence" is one of several sentences in the
standard that says that two types are compatible. Unless at least one of those
sentences applies in any given context, the types are incompatible. None of
those sentences applies to this context, which is why we're all perfectly in
agreement with you that these two types are incompatible.
Our point of disagreement with you is about the supposed requirement that they
be compatible, which exists only in your head.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
... are compatible if their tags and members
satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are completed
anywhere within their respective translation units, then the following
additional requirements apply: there shall be a one-to-one
correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values. "
There's no need to go into all of those details for types declared in the same
translation unit. If declared in the same translation unit, even two different
struct types that meet all of those requirements would be incompatible with
each other.
Just the fact they are defined in the same translation unit does not
mean they are compatible.
Correct, as I said above, they are not compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
According to this, the two structures are not compatible ...
That's true, but not for the reason you seem to think - they're incompatible
simply because none of the rules that say two types are compatible apply to
these types. The part you quoted from 6.2.7p1 doesn't apply simply because they
are declared in the same translation unit.
They still aren't compatible.
Which is what I said above.
Post by Jerry Stuckle
Post by j***@verizon.net
No one has ever disagreed with you about struct ct_child being incompatible
with struct ct_parent. I pointed that out to you in the same message you
responded to. So, what? There's no applicable requirement that they be
compatible.
But that is the specific question Chris asked.
No, he didn't ask whether they were compatible. He asked whether the conversion
was permitted. The conversion doesn't require that they be compatible, so the
fact that they aren't isn't a problem.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
... (but I also
said it would probably work with most compilers nowadays).
It's required to work on any compiler conforming to any version of the C
standard. For that matter, it's also required to work for the first non-static
data member of a layout-compatible class in C++ (9.2p19, C++2011).
If they are compatible.
There's no such requirement in the standard.
Post by Jerry Stuckle
But they are not compatible because they have
different definitions.
Agreed, as I've said multiple times over.
Post by Jerry Stuckle
Post by j***@verizon.net
From past experience with you, I expect that any reply you make to this message
will be non-responsive. Just to make it clearer that you're failing to be
responsive, I'm going to number the following questions, and for each question,
identify what would constitute a responsive answer to the question.
I respond. And I don't agree with you. Show me where the standard says
the two are compatible.
I've repeatedly said that they aren't compatible. Show me where the standard
requires them to be compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
I'm going to cite this here, because the citation near the top of the message
..
Post by Jerry Stuckle
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
...
Post by Jerry Stuckle
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
1. What requirement of the C standard do you think is violated by the code
above, due to the universally acknowledged fact that struct ct_parent is not
compatible with struct ct_child?
A responsive answer will at least identify the precise paragraph in the
standard which imposes such a requirement, and preferably would quote the text
expressing that requirement.
You provided no such citation - non-responsive.

I've asked you to cite the requirement that they be compatible. You've failed to
do so. That's the closest I'll ever get to having you admit that there is no
such requirement. I'll take it as such, though that is quite manifestly contrary
to your intent.
Post by Jerry Stuckle
They do not have the same definition, and C does not provide a way to
convert one user type to another.
True, and this code does nothing of the kind. It converts a pointer to one user
defined type into a pointer to another user defined type, and 6.3.2.3p7 is where
the C standard provides a way to do that. Note that the two types covered by a
6.3.2.3p7 conversion will, in general, not be compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
2. If you were right about "suitably converted" requiring that the types be
compatible, then since the struct ct_child is a struct type, such a pointer
could be "suitably converted" only if it's initial member has the same type as
the struct itself. Do you agree?
Responsive answers will either say "Yes" or "No", or provide an explanation why
neither of those two answers is appropriate. I'll abbreviate this as Y/N/O
further down.
You can't convert something to an incompatible type.
Sure you can; most conversions change something from one type to an incompatible
type. For instance, char->long double _Complex is perfectly permissible
conversion, and those types are very definitely not compatible. If the types
were compatible, there'd be no need for conversion - an object of either type could be used anywhere that an object of the other type was specified, without any conversion required.

So you answered neither Yes, nor No, nor provided an explanation why neither answer is appropriate. Non-responsive.
Post by Jerry Stuckle
Post by j***@verizon.net
3. The standard prohibits a struct type from containing a member of the same
type (6.7.2.1p3). Do you agree?
Responsive answers will be Y/N/O.
The same struct can't have two members of the same name, but two
different structs very well can.
I didn't ask about two members of the same name, I asked about one member, of the same type as the struct itself. That's because it's precisely that prohibited case which is the only way your criterion for "suitably converted" could be satisfied.

You didn't answer Y/N/O - non-responsive.
Post by Jerry Stuckle
Post by j***@verizon.net
4. If you answered "Yes" to questions 2 and 3, and if you were correct that the
types had to be compatible in order for the conversion to be "suitable", it
would therefore be impossible, in strictly conforming code, for the conversion
to ever be suitable? Do you agree?
Responsive answers will be Y/N/O.
See above.
I see no answers to either question 2 or 3, just non-responsive responses. I also see no answer to question 4 above.
Post by Jerry Stuckle
Post by j***@verizon.net
5. If you answered "Yes" to question 4, then what do you think was the reason
why the committee wasted time writing 6.7.2.1p15, to describe a situation that
could never come up?
A responsive answer will actually identify a reason.
There are other types of pointers, also. But just because a pointer can
be converted to point at a structure does not mean the structures are
compatible. ...
Perfectly correct, and irrelevant.
Post by Jerry Stuckle
... Point me where it says they are.
Point to me where it's required that they be compatible - which was question #1.
Post by Jerry Stuckle
And why don't you ask the C standards committee why they said this?
Because I understand precisely why they said it - to allow code of the kind you're claiming is prohibited. Which is what that clause does. It's your misinterpretation of what "suitably converted" means, that renders the clause pointless. Since I don't share that misinterpretation, I don't have any problem with that clause.
Post by Jerry Stuckle
Post by j***@verizon.net
6. If you answered anything other than "Yes" to question 4, please provide an
example of code that meets your understanding of the requirements for "suitably
converted", as that phrase is used in 6.7.2.1p15.
A responsive answer will provide source code that includes a declaration of a
struct type, and a conversion of a pointer to the struct type into a pointer to
the type of it's first member. It will also conform to the requirement that you
believe exists, in order for that conversion to have defined behavior - namely,
that those two types be compatible. It will also not violate 6.7.2.1p3. Good
luck!
Other than two structures defined the same way, I don't know of any way
within the standard to ensure they are compatible. Why don't you ask
the standards committee to provide you with an example?
Because I would expect the committee to show me code that looks like the code you've rejected, and to agree with me that it is allowed. It's only your misinterpretation of "suitably converted" that renders creating an example problematic. A correct understanding of that term makes it trivial to create examples.

Since you have, as predicted, completely failed to make a responsive response to any of my questions, I won't bother engaging you further on this topic. That was you last opportunity to entangle me in your nonsense.
What I didn't expect was for you to display so many new misunderstandings:

1. Thinking that Chris was asking about the compatibility of the types, rather than the legitimacy of the conversion.
2. Thinking that this code attempts to convert an object of type ct_child to the type ct_parent.
3. Thinking that it's not permitted for a conversion to change something from
one type to an incompatible type, when in fact, that's what virtually all
conversions do.
4. Thinking I was asking about two members of the same name, rather than one
member of the same type as the struct itself.
5. Thinking that my question about the pointlessness of 6.7.2.1p15 was based my understanding of that clause; it's only your misunderstanding that renders it
pointless.

Your inability to understand so many points in this discussion further argues
against bothering to continue discussing it with you.
James Kuyper
2017-07-27 15:11:04 UTC
Permalink
Raw Message
Post by j***@verizon.net
Post by Jerry Stuckle
...
...
Post by j***@verizon.net
Post by Jerry Stuckle
You can't convert something to an incompatible type.
Sure you can; most conversions change something from one type to an incompatible
type. For instance, char->long double _Complex is perfectly permissible
conversion, and those types are very definitely not compatible. If the types
were compatible, there'd be no need for conversion - an object of either type
dould be used anywhere that an object of the other type was specified,
without any conversion required.
I got a bit sloppy there. That last sentence should have been about
values, rather than objects.

...
...
Post by j***@verizon.net
3. Thinking that it's not permitted for a conversion to change something from
one type to an incompatible type, when in fact, that's what virtually all
conversions do.
Let me expand on that by reviewing section 6.3.1 "Conversions":

6.3.1.2: Any scalar value may be converted to _Bool. The only scalar
type compatible with _Bool is _Bool. If it already had that type, no
conversion would be needed.

6.3.1.3p2: Any integer value may be converted to any unsigned type. The
only integer type that is compatible with any particular unsigned type
is that type itself (or possibly some enumeration types), and if it
already had that type, no conversion would be needed.

6.3.1.3p3: Any integer value may be safely to converted to any signed
type that it can be represented in. The only integer type that is
compatible with any given signed type is that same type (or possibly
some enumerated types). If the value were already of that type, no
conversion would be needed.

6.3.1.4p1: Any real floating point value my be safely converted (except
for the loss of the fractional part) to any integer type capable of
representing the integer part. No floating point type is compatible with
any integer type.

6.3.1.4p2: Any integer value may be safely converted (except possibly
with a loss of precision) to any real floating point type capable of
representing that value (possibly with a loss of precision). No integer
type is compatible with any floating point type.

6.3.1.5: Any real floating point value may be safely converted to any
other real floating point type capable of representing that value
(possibly with a loss of precision). The only type that is compatible
with a given floating point type is that type itself. If the value were
already of that type, no conversion would be needed.

6.3.1.6: Any complex floating point value may be converted to any other
complex floating point type capable of representing that value (possibly
with loss of precision). The only type that is compatible with a given
floating point type is that type itself. If the value were already of
that type, no conversion would be needed.

6.3.1.7p1: Any value of real floating point type may be converted to any
complex floating point type capable of representing that value (possibly
with loss of precision). No real floating point type is compatible with
any complex floating point type.

6.3.1.7p2: Any value of complex floating point type may be converted to
any real floating point type (with loss of the imaginary component of
that value) that is capable of representing the real component of that
value (possibly with loss of precision). No complex floating point type
is compatible with any real floating point type.

6.3.2.1p2: lvalue conversions remove any qualifications that apply to
the original lvalue. No qualified type is compatible with it's
corresponding unqualified type.

6.3.2.1p3: In most contexts, an lvalue of array type get implicitly
converted into a pointer to the first element of the array. No array
type is compatible with it's element type.

6.3.2.1p4: In most contexts, a function designator get implicitly
converted converted into a pointer to the function. No function type is
compatible with the corresponding pointer type.

6.3.2.2: Any expression may be converted to void; no type other than
void is compatible with void, and if the expression had that type, no
conversion would be needed.

6.3.2.3p1: A pointer to void may be converted to or from a pointer to
any object type. pointer to void is the only type that is compatible
with pointer to void, and if the pointer already had that type, no
conversion would be needed.

6.3.2.3p2: A pointer to a type that doesn't have a qualifier (such as
const or volatile) may be converted to a pointer that does have that
qualifier. No pointer type is compatible with a pointer that points to a
differently qualified type.

6.3.2.3p3: A null pointer constant be be converted to a pointer type. A
null pointer constant may have an integer type. No integer type is
compatible with any pointer type.

6.3.2.3p4: A null pointer may be converted to another pointer type. The
only other pointer types that are compatible with a pointer to a given
type are pointers to a compatible type. If the pointer were of such a
type, no conversion would be needed.

6.3.2.3p5: An integer may be converted to any pointer type, though the
only integer types for which such a conversion guaranteed to be useful
are [u]intprt_t. No integer type is compatible with any pointer type.

6.3.2.3p6: Any pointer type may be safely converted to any integer type
capable of representing the result of the conversion. No pointer type is
compatible with any integer type.

6.3.2.3p7: Any pointer to an object type may be safely converted to a
pointer to a different object type, if it's correctly aligned for that
type. The only types that are compatible with a given pointer to object
type are pointers to compatible object types. If a pointer had such a
type, no conversion would be needed.

6.3.2.3p8: Any pointer to a function type may be converted to a pointer
to a different function type. The only types that are compatible with a
given pointer to function type are pointers to compatible function
types. If a pointer had such a type, no conversion would be needed.
Jerry Stuckle
2017-07-28 00:25:37 UTC
Permalink
Raw Message
Post by James Kuyper
Post by j***@verizon.net
Post by Jerry Stuckle
...
...
Post by j***@verizon.net
Post by Jerry Stuckle
You can't convert something to an incompatible type.
Sure you can; most conversions change something from one type to an incompatible
type. For instance, char->long double _Complex is perfectly permissible
conversion, and those types are very definitely not compatible. If the types
were compatible, there'd be no need for conversion - an object of either type
dould be used anywhere that an object of the other type was specified,
without any conversion required.
I got a bit sloppy there. That last sentence should have been about
values, rather than objects.
...
...
Post by j***@verizon.net
3. Thinking that it's not permitted for a conversion to change something from
one type to an incompatible type, when in fact, that's what virtually all
conversions do.
6.3.1.2: Any scalar value may be converted to _Bool. The only scalar
type compatible with _Bool is _Bool. If it already had that type, no
conversion would be needed.
6.3.1.3p2: Any integer value may be converted to any unsigned type. The
only integer type that is compatible with any particular unsigned type
is that type itself (or possibly some enumeration types), and if it
already had that type, no conversion would be needed.
6.3.1.3p3: Any integer value may be safely to converted to any signed
type that it can be represented in. The only integer type that is
compatible with any given signed type is that same type (or possibly
some enumerated types). If the value were already of that type, no
conversion would be needed.
6.3.1.4p1: Any real floating point value my be safely converted (except
for the loss of the fractional part) to any integer type capable of
representing the integer part. No floating point type is compatible with
any integer type.
6.3.1.4p2: Any integer value may be safely converted (except possibly
with a loss of precision) to any real floating point type capable of
representing that value (possibly with a loss of precision). No integer
type is compatible with any floating point type.
6.3.1.5: Any real floating point value may be safely converted to any
other real floating point type capable of representing that value
(possibly with a loss of precision). The only type that is compatible
with a given floating point type is that type itself. If the value were
already of that type, no conversion would be needed.
6.3.1.6: Any complex floating point value may be converted to any other
complex floating point type capable of representing that value (possibly
with loss of precision). The only type that is compatible with a given
floating point type is that type itself. If the value were already of
that type, no conversion would be needed.
6.3.1.7p1: Any value of real floating point type may be converted to any
complex floating point type capable of representing that value (possibly
with loss of precision). No real floating point type is compatible with
any complex floating point type.
6.3.1.7p2: Any value of complex floating point type may be converted to
any real floating point type (with loss of the imaginary component of
that value) that is capable of representing the real component of that
value (possibly with loss of precision). No complex floating point type
is compatible with any real floating point type.
6.3.2.1p2: lvalue conversions remove any qualifications that apply to
the original lvalue. No qualified type is compatible with it's
corresponding unqualified type.
6.3.2.1p3: In most contexts, an lvalue of array type get implicitly
converted into a pointer to the first element of the array. No array
type is compatible with it's element type.
6.3.2.1p4: In most contexts, a function designator get implicitly
converted converted into a pointer to the function. No function type is
compatible with the corresponding pointer type.
6.3.2.2: Any expression may be converted to void; no type other than
void is compatible with void, and if the expression had that type, no
conversion would be needed.
6.3.2.3p1: A pointer to void may be converted to or from a pointer to
any object type. pointer to void is the only type that is compatible
with pointer to void, and if the pointer already had that type, no
conversion would be needed.
6.3.2.3p2: A pointer to a type that doesn't have a qualifier (such as
const or volatile) may be converted to a pointer that does have that
qualifier. No pointer type is compatible with a pointer that points to a
differently qualified type.
6.3.2.3p3: A null pointer constant be be converted to a pointer type. A
null pointer constant may have an integer type. No integer type is
compatible with any pointer type.
6.3.2.3p4: A null pointer may be converted to another pointer type. The
only other pointer types that are compatible with a pointer to a given
type are pointers to a compatible type. If the pointer were of such a
type, no conversion would be needed.
6.3.2.3p5: An integer may be converted to any pointer type, though the
only integer types for which such a conversion guaranteed to be useful
are [u]intprt_t. No integer type is compatible with any pointer type.
6.3.2.3p6: Any pointer type may be safely converted to any integer type
capable of representing the result of the conversion. No pointer type is
compatible with any integer type.
6.3.2.3p7: Any pointer to an object type may be safely converted to a
pointer to a different object type, if it's correctly aligned for that
type. The only types that are compatible with a given pointer to object
type are pointers to compatible object types. If a pointer had such a
type, no conversion would be needed.
6.3.2.3p8: Any pointer to a function type may be converted to a pointer
to a different function type. The only types that are compatible with a
given pointer to function type are pointers to compatible function
types. If a pointer had such a type, no conversion would be needed.
OK, so where does it say the two structures are compatible? I don't see
it in any of these paragraphs.
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
James Kuyper
2017-07-28 03:02:14 UTC
Permalink
Raw Message
Post by James Kuyper
Post by j***@verizon.net
Post by Jerry Stuckle
...
...
Post by j***@verizon.net
Post by Jerry Stuckle
You can't convert something to an incompatible type.
Sure you can; most conversions change something from one type to an incompatible
type. For instance, char->long double _Complex is perfectly permissible
conversion, and those types are very definitely not compatible. If the types
were compatible, there'd be no need for conversion - an object of either type
dould be used anywhere that an object of the other type was specified,
without any conversion required.
I got a bit sloppy there. That last sentence should have been about
values, rather than objects.
...
...
Post by j***@verizon.net
3. Thinking that it's not permitted for a conversion to change something from
one type to an incompatible type, when in fact, that's what virtually all
conversions do.
...

Just for fun - a program that is intended to

1. Be strictly conforming.
2. Demonstrate every single type of conversion listed in 6.3. I've
placed comments identifying the relevant clause as close as I could to
the location where the corresponding conversion occurs.
3. Have every single one of those conversions convert something to an
incompatible type.

Please let me know of any cases where I failed to meet those objectives,
and I'll try to figure out how to fix it up.

Note: I tried to make this as short a program as I could. As a result,
it's completely ridiculous code, written in a very bad style, whose
execution achieves no useful purpose, has no observable behavior, and
could therefore be optimized down to the equivalent of "int main(void){}".
None of that matters - the purpose this code is to demonstrate that
conversions to incompatible types are not prohibited, they're not even
rare, they are in fact the norm. It's conversions to a compatible type
which are rare.

#include <complex.h>
#include <stdarg.h>
#include <stdint.h>

static long double _Complex func(const long vl, ...)
{
va_list ap;
(void) /* 6.3.2.2 */
vl /* 6.3.2.1p2 */
;

va_start(ap, vl);
return /* 6.3.1.6 */
va_arg(ap, double) + /* 6.3.1.6 */
_Complex_I /* 6.3.1.7p1 */
;
}

int main(void)
{
signed char array[] = {-1, 0};

unsigned char uc = /* 6.3.1.3p2 */
(int) /* 6.3.1.4p1 */
(float) /* 6.3.1.7p2 */
((long double _Complex(*)(const long,...)) /* 6.3.2.3p8 */
(void(*)(void)) /* 6.3.2.1p4 */
func) ((_Bool) /* 6.3.1.2 */
(double*) /* 6.3.2.3p4 */
(const void*) /* 6.3.2.3p3 */
0, (float) /* 6.3.1.4p2 */
- /* 6.3.1.3p3 */
array /* 6.3.2.1p3 */
[0] /* 6.3.1.5 */
);

(signed char*) /* 6.3.2.3p7 */
(unsigned char *) /* 6.3.2.3p5 */
(uintptr_t) /* 6.3.2.3p6 */
&uc;
}

Jerry Stuckle
2017-07-28 00:23:45 UTC
Permalink
Raw Message
Post by j***@verizon.net
Post by Jerry Stuckle
Post by j***@verizon.net
...
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
The key here is "suitably converted". According to 6.7.2, The two types
are not compatible, so there is no "suitable conversion".
If "suitably converted" meant that they had to be the same type, then the
only time 6.7.2.1p15 could possibly apply would be if the initial member of
a struct had the same type as the struct itself. But that's expressly
prohibited: "... a structure shall not contain an instance of itself ..."
(6.7.2.1p3), for what I hope are perfectly obvious reasons.
Can you show me an example of a "suitably converted" "pointer to a
structure object" that does point "to its initial member"? If not, what is
your understanding of why the standard bothers talking about a situation
that could never come up?
Sorry, finger c heck on my part. The applicable paragraph is 6.2.7 p1,
"Moreover, two structure, union, or enumerated types declared in
separate translation units ...
These types are declared in the same translation unit, so that's sufficient to render this sentence inapplicable.
Even if they're in the same translation unit, it makes no difference.
They are still not compatible.
Which is what I just said. "This sentence" is one of several sentences in the
standard that says that two types are compatible. Unless at least one of those
sentences applies in any given context, the types are incompatible. None of
those sentences applies to this context, which is why we're all perfectly in
agreement with you that these two types are incompatible.
Our point of disagreement with you is about the supposed requirement that they
be compatible, which exists only in your head.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
... are compatible if their tags and members
satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are completed
anywhere within their respective translation units, then the following
additional requirements apply: there shall be a one-to-one
correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in the
same order. For two structures or unions, corresponding bit-fields shall
have the same widths. For two enumerations, corresponding members shall
have the same values. "
There's no need to go into all of those details for types declared in the same
translation unit. If declared in the same translation unit, even two different
struct types that meet all of those requirements would be incompatible with
each other.
Just the fact they are defined in the same translation unit does not
mean they are compatible.
Correct, as I said above, they are not compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
According to this, the two structures are not compatible ...
That's true, but not for the reason you seem to think - they're incompatible
simply because none of the rules that say two types are compatible apply to
these types. The part you quoted from 6.2.7p1 doesn't apply simply because they
are declared in the same translation unit.
They still aren't compatible.
Which is what I said above.
Post by Jerry Stuckle
Post by j***@verizon.net
No one has ever disagreed with you about struct ct_child being incompatible
with struct ct_parent. I pointed that out to you in the same message you
responded to. So, what? There's no applicable requirement that they be
compatible.
But that is the specific question Chris asked.
No, he didn't ask whether they were compatible. He asked whether the conversion
was permitted. The conversion doesn't require that they be compatible, so the
fact that they aren't isn't a problem.
Post by Jerry Stuckle
Post by j***@verizon.net
Post by Jerry Stuckle
... (but I also
said it would probably work with most compilers nowadays).
It's required to work on any compiler conforming to any version of the C
standard. For that matter, it's also required to work for the first non-static
data member of a layout-compatible class in C++ (9.2p19, C++2011).
If they are compatible.
There's no such requirement in the standard.
Post by Jerry Stuckle
But they are not compatible because they have
different definitions.
Agreed, as I've said multiple times over.
Post by Jerry Stuckle
Post by j***@verizon.net
From past experience with you, I expect that any reply you make to this message
will be non-responsive. Just to make it clearer that you're failing to be
responsive, I'm going to number the following questions, and for each question,
identify what would constitute a responsive answer to the question.
I respond. And I don't agree with you. Show me where the standard says
the two are compatible.
I've repeatedly said that they aren't compatible. Show me where the standard
requires them to be compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
I'm going to cite this here, because the citation near the top of the message
..
Post by Jerry Stuckle
struct ct_parent
{
int parent_a;
};
struct ct_child
{
struct ct_parent parent;
int child_a;
};
...
Post by Jerry Stuckle
struct ct_child child = { { 1234 }, 5678 };
struct ct_parent* parent = (struct ct_parent*)&child; // Kosher?
1. What requirement of the C standard do you think is violated by the code
above, due to the universally acknowledged fact that struct ct_parent is not
compatible with struct ct_child?
A responsive answer will at least identify the precise paragraph in the
standard which imposes such a requirement, and preferably would quote the text
expressing that requirement.
You provided no such citation - non-responsive.
I've asked you to cite the requirement that they be compatible. You've failed to
do so. That's the closest I'll ever get to having you admit that there is no
such requirement. I'll take it as such, though that is quite manifestly contrary
to your intent.
Post by Jerry Stuckle
They do not have the same definition, and C does not provide a way to
convert one user type to another.
True, and this code does nothing of the kind. It converts a pointer to one user
defined type into a pointer to another user defined type, and 6.3.2.3p7 is where
the C standard provides a way to do that. Note that the two types covered by a
6.3.2.3p7 conversion will, in general, not be compatible.
Post by Jerry Stuckle
Post by j***@verizon.net
2. If you were right about "suitably converted" requiring that the types be
compatible, then since the struct ct_child is a struct type, such a pointer
could be "suitably converted" only if it's initial member has the same type as
the struct itself. Do you agree?
Responsive answers will either say "Yes" or "No", or provide an explanation why
neither of those two answers is appropriate. I'll abbreviate this as Y/N/O
further down.
You can't convert something to an incompatible type.
Sure you can; most conversions change something from one type to an incompatible
type. For instance, char->long double _Complex is perfectly permissible
conversion, and those types are very definitely not compatible. If the types
were compatible, there'd be no need for conversion - an object of either type could be used anywhere that an object of the other type was specified, without any conversion required.
So you answered neither Yes, nor No, nor provided an explanation why neither answer is appropriate. Non-responsive.
Post by Jerry Stuckle
Post by j***@verizon.net
3. The standard prohibits a struct type from containing a member of the same
type (6.7.2.1p3). Do you agree?
Responsive answers will be Y/N/O.
The same struct can't have two members of the same name, but two
different structs very well can.
I didn't ask about two members of the same name, I asked about one member, of the same type as the struct itself. That's because it's precisely that prohibited case which is the only way your criterion for "suitably converted" could be satisfied.
You didn't answer Y/N/O - non-responsive.
Post by Jerry Stuckle
Post by j***@verizon.net
4. If you answered "Yes" to questions 2 and 3, and if you were correct that the
types had to be compatible in order for the conversion to be "suitable", it
would therefore be impossible, in strictly conforming code, for the conversion
to ever be suitable? Do you agree?
Responsive answers will be Y/N/O.
See above.
I see no answers to either question 2 or 3, just non-responsive responses. I also see no answer to question 4 above.
Post by Jerry Stuckle
Post by j***@verizon.net
5. If you answered "Yes" to question 4, then what do you think was the reason
why the committee wasted time writing 6.7.2.1p15, to describe a situation that
could never come up?
A responsive answer will actually identify a reason.
There are other types of pointers, also. But just because a pointer can
be converted to point at a structure does not mean the structures are
compatible. ...
Perfectly correct, and irrelevant.
Post by Jerry Stuckle
... Point me where it says they are.
Point to me where it's required that they be compatible - which was question #1.
Post by Jerry Stuckle
And why don't you ask the C standards committee why they said this?
Because I understand precisely why they said it - to allow code of the kind you're claiming is prohibited. Which is what that clause does. It's your misinterpretation of what "suitably converted" means, that renders the clause pointless. Since I don't share that misinterpretation, I don't have any problem with that clause.
Post by Jerry Stuckle
Post by j***@verizon.net
6. If you answered anything other than "Yes" to question 4, please provide an
example of code that meets your understanding of the requirements for "suitably
converted", as that phrase is used in 6.7.2.1p15.
A responsive answer will provide source code that includes a declaration of a
struct type, and a conversion of a pointer to the struct type into a pointer to
the type of it's first member. It will also conform to the requirement that you
believe exists, in order for that conversion to have defined behavior - namely,
that those two types be compatible. It will also not violate 6.7.2.1p3. Good
luck!
Other than two structures defined the same way, I don't know of any way
within the standard to ensure they are compatible. Why don't you ask
the standards committee to provide you with an example?
Because I would expect the committee to show me code that looks like the code you've rejected, and to agree with me that it is allowed. It's only your misinterpretation of "suitably converted" that renders creating an example problematic. A correct understanding of that term makes it trivial to create examples.
Show where they say the two structure types are compatible. I'm not
talking about "suitably converted" pointers - for a pointer to be
"suitably converted", the two types must be compatible. Show me where
THAT is defined in the standard.
Post by j***@verizon.net
Since you have, as predicted, completely failed to make a responsive response to any of my questions, I won't bother engaging you further on this topic. That was you last opportunity to entangle me in your nonsense.
The standard defines what IS possible, not what IS NOT possible. If it
is not specifically defined in the standard, it is at best undefined
behavior.
Post by j***@verizon.net
1. Thinking that Chris was asking about the compatibility of the types, rather than the legitimacy of the conversion.
2. Thinking that this code attempts to convert an object of type ct_child to the type ct_parent.
3. Thinking that it's not permitted for a conversion to change something from
one type to an incompatible type, when in fact, that's what virtually all
conversions do.
4. Thinking I was asking about two members of the same name, rather than one
member of the same type as the struct itself.
5. Thinking that my question about the pointlessness of 6.7.2.1p15 was based my understanding of that clause; it's only your misunderstanding that renders it
pointless.
Your inability to understand so many points in this discussion further argues
against bothering to continue discussing it with you.
I understand the points. But neither you nor anyone else has shown
where the two different structs are compatible according to the
standard. And if you are going to say the pointers are compatible if
there is a "suitable conversion", you need to show where that "suitable
conversion" is defined for these types.
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
Loading...