Is this type punning well defined?
I have structure like below.
struct result{
int a;
int b;
int c;
int d;
}
and union like below.
union convert{
int arr[4];
struct result res;
}
and I type pun as below.
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?
printf("%d %dn", pointer->res.a, pointer->res.b);
c language-lawyer
add a comment |
I have structure like below.
struct result{
int a;
int b;
int c;
int d;
}
and union like below.
union convert{
int arr[4];
struct result res;
}
and I type pun as below.
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?
printf("%d %dn", pointer->res.a, pointer->res.b);
c language-lawyer
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
2
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
1
Hmmm, Ifstatic_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.
– chux
Jan 17 at 16:53
add a comment |
I have structure like below.
struct result{
int a;
int b;
int c;
int d;
}
and union like below.
union convert{
int arr[4];
struct result res;
}
and I type pun as below.
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?
printf("%d %dn", pointer->res.a, pointer->res.b);
c language-lawyer
I have structure like below.
struct result{
int a;
int b;
int c;
int d;
}
and union like below.
union convert{
int arr[4];
struct result res;
}
and I type pun as below.
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1; // Here is my question, is it well defined?
printf("%d %dn", pointer->res.a, pointer->res.b);
c language-lawyer
c language-lawyer
edited Jan 17 at 14:30
AndyG
26.7k77097
26.7k77097
asked Jan 17 at 14:23
KBlrKBlr
18210
18210
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
2
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
1
Hmmm, Ifstatic_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.
– chux
Jan 17 at 16:53
add a comment |
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
2
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
1
Hmmm, Ifstatic_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.
– chux
Jan 17 at 16:53
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
2
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
2
2
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
1
1
Hmmm, If
static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.– chux
Jan 17 at 16:53
Hmmm, If
static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.– chux
Jan 17 at 16:53
add a comment |
4 Answers
4
active
oldest
votes
pointer->res.a
is fine but the behaviour of pointer->res.b
is undefined.
There could be an arbitrary amount of padding between the a
and b
members.
Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
Jan 17 at 16:13
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
@LanguageLawyer:struct A { int x; };
andstruct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only theint x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just theint
.
– Eric Postpischil
Jan 17 at 20:14
|
show 9 more comments
Is this type punning well defined?
struct result{
int a,b,c,d;
}
union convert {
int arr[4];
struct result res;
}
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;
(union convert *) arr1
risks alignment failure.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8
There is no requirement that union convert
and int
share the same alignment. union convert
requirements may exceed int
for example.
Consider this possibility: arr1
lives on int
street where all addresses are multiple of 4. union
and struct
friends lives on "multiple of 8" street. arr1
might have address 0x1004 (not a multiple of 8).
In 2019, alignment failures are more commonly seen with char
(needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.
This type punning is not well defined.
Additional concerns
Other answers and comments discuss padding issues, which further identifies trouble.
@Eric Postpischil comment about improper access with pointer->res.a
adds more reasons to consider this UB.
add a comment |
C imposes no rule about how much padding is left between 2 consecutive members of a structure.
This is why the implementations define many #pragma directives -- specially to change this behaviour.
So, as the answer of Bathsheba says, ...->b
is undefined.
I answered the very same question some time ago, here.
add a comment |
Pointer punning is not safe. Use real union punning instead.
Assumptions: the struct is properly packed (no padding between the members)
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) result{
int a;
int b;
int c;
int d;
};
union convert{
int arr[4];
struct result res;
};
volatile int arr1[4];
void foo(void)
{
union convert cnv;
memcpy(&cnv, (void *)arr1, sizeof(arr1));
printf("%d %dn", cnv.res.a, cnv.res.b);
}
all modern compilers will optimize out the memcpy
call
https://godbolt.org/z/4qtRIF
.LC0:
.string "%d %dn"
foo:
mov rsi, QWORD PTR arr1[rip]
xor eax, eax
mov rdi, QWORD PTR arr1[rip+8]
mov edi, OFFSET FLAT:.LC0
mov rdx, rsi
sar rdx, 32
jmp printf
Why thevolatile
global?
– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54237976%2fis-this-type-punning-well-defined%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
pointer->res.a
is fine but the behaviour of pointer->res.b
is undefined.
There could be an arbitrary amount of padding between the a
and b
members.
Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
Jan 17 at 16:13
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
@LanguageLawyer:struct A { int x; };
andstruct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only theint x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just theint
.
– Eric Postpischil
Jan 17 at 20:14
|
show 9 more comments
pointer->res.a
is fine but the behaviour of pointer->res.b
is undefined.
There could be an arbitrary amount of padding between the a
and b
members.
Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
Jan 17 at 16:13
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
@LanguageLawyer:struct A { int x; };
andstruct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only theint x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just theint
.
– Eric Postpischil
Jan 17 at 20:14
|
show 9 more comments
pointer->res.a
is fine but the behaviour of pointer->res.b
is undefined.
There could be an arbitrary amount of padding between the a
and b
members.
Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.
pointer->res.a
is fine but the behaviour of pointer->res.b
is undefined.
There could be an arbitrary amount of padding between the a
and b
members.
Some compilers allow you to specify that there is no padding between members but of course then you are giving up portability.
answered Jan 17 at 14:33


BathshebaBathsheba
179k27254382
179k27254382
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
Jan 17 at 16:13
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
@LanguageLawyer:struct A { int x; };
andstruct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only theint x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just theint
.
– Eric Postpischil
Jan 17 at 20:14
|
show 9 more comments
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
Jan 17 at 16:13
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
@LanguageLawyer:struct A { int x; };
andstruct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only theint x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just theint
.
– Eric Postpischil
Jan 17 at 20:14
1
1
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
@KBlr: Yep! Just not portable
– AndyG
Jan 17 at 14:37
3
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.– Eric Postpischil
Jan 17 at 16:13
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.– Eric Postpischil
Jan 17 at 16:13
1
1
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
@EricPostpischil So the aliasing rule applies not only to the "final" expression which is actually used to access (read or modify) an object, but to all glvalue subexpressions of the "final" expression?
– Language Lawyer
Jan 17 at 18:22
1
1
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
@EricPostpischil What I don't like in this aliasing rules, they talk about "expression used to access". I'm not sure does it mean only the "final" expression or all the subexpressions are also "used to access". Any authoritative references here? Also, arrays of different structures with identical definitions did not understand this.
– Language Lawyer
Jan 17 at 18:59
1
1
@LanguageLawyer:
struct A { int x; };
and struct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int
.– Eric Postpischil
Jan 17 at 20:14
@LanguageLawyer:
struct A { int x; };
and struct B { int x; };
have identical definitions but are different types. The C standard says they are not compatible, and one may not alias the other. If only the int x
mattered, the aliasing rule would be useless. It is the fact that one structure cannot alias the other that enables optimization based on the aliasing rules. The aliasing rules must apply to the structures lvalues, not just the int
.– Eric Postpischil
Jan 17 at 20:14
|
show 9 more comments
Is this type punning well defined?
struct result{
int a,b,c,d;
}
union convert {
int arr[4];
struct result res;
}
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;
(union convert *) arr1
risks alignment failure.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8
There is no requirement that union convert
and int
share the same alignment. union convert
requirements may exceed int
for example.
Consider this possibility: arr1
lives on int
street where all addresses are multiple of 4. union
and struct
friends lives on "multiple of 8" street. arr1
might have address 0x1004 (not a multiple of 8).
In 2019, alignment failures are more commonly seen with char
(needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.
This type punning is not well defined.
Additional concerns
Other answers and comments discuss padding issues, which further identifies trouble.
@Eric Postpischil comment about improper access with pointer->res.a
adds more reasons to consider this UB.
add a comment |
Is this type punning well defined?
struct result{
int a,b,c,d;
}
union convert {
int arr[4];
struct result res;
}
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;
(union convert *) arr1
risks alignment failure.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8
There is no requirement that union convert
and int
share the same alignment. union convert
requirements may exceed int
for example.
Consider this possibility: arr1
lives on int
street where all addresses are multiple of 4. union
and struct
friends lives on "multiple of 8" street. arr1
might have address 0x1004 (not a multiple of 8).
In 2019, alignment failures are more commonly seen with char
(needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.
This type punning is not well defined.
Additional concerns
Other answers and comments discuss padding issues, which further identifies trouble.
@Eric Postpischil comment about improper access with pointer->res.a
adds more reasons to consider this UB.
add a comment |
Is this type punning well defined?
struct result{
int a,b,c,d;
}
union convert {
int arr[4];
struct result res;
}
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;
(union convert *) arr1
risks alignment failure.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8
There is no requirement that union convert
and int
share the same alignment. union convert
requirements may exceed int
for example.
Consider this possibility: arr1
lives on int
street where all addresses are multiple of 4. union
and struct
friends lives on "multiple of 8" street. arr1
might have address 0x1004 (not a multiple of 8).
In 2019, alignment failures are more commonly seen with char
(needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.
This type punning is not well defined.
Additional concerns
Other answers and comments discuss padding issues, which further identifies trouble.
@Eric Postpischil comment about improper access with pointer->res.a
adds more reasons to consider this UB.
Is this type punning well defined?
struct result{
int a,b,c,d;
}
union convert {
int arr[4];
struct result res;
}
int arr1[4] = {1,2,3,5};
union convert *pointer = (union convert *) arr1;
(union convert *) arr1
risks alignment failure.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 8
There is no requirement that union convert
and int
share the same alignment. union convert
requirements may exceed int
for example.
Consider this possibility: arr1
lives on int
street where all addresses are multiple of 4. union
and struct
friends lives on "multiple of 8" street. arr1
might have address 0x1004 (not a multiple of 8).
In 2019, alignment failures are more commonly seen with char
(needing 1) and other types needing 2 or more. In OP's select case, I doubt a real platform will have alignment issues, yet incorrect alignment remains possible.
This type punning is not well defined.
Additional concerns
Other answers and comments discuss padding issues, which further identifies trouble.
@Eric Postpischil comment about improper access with pointer->res.a
adds more reasons to consider this UB.
edited Jan 17 at 19:12
answered Jan 17 at 17:01


chuxchux
83.2k872151
83.2k872151
add a comment |
add a comment |
C imposes no rule about how much padding is left between 2 consecutive members of a structure.
This is why the implementations define many #pragma directives -- specially to change this behaviour.
So, as the answer of Bathsheba says, ...->b
is undefined.
I answered the very same question some time ago, here.
add a comment |
C imposes no rule about how much padding is left between 2 consecutive members of a structure.
This is why the implementations define many #pragma directives -- specially to change this behaviour.
So, as the answer of Bathsheba says, ...->b
is undefined.
I answered the very same question some time ago, here.
add a comment |
C imposes no rule about how much padding is left between 2 consecutive members of a structure.
This is why the implementations define many #pragma directives -- specially to change this behaviour.
So, as the answer of Bathsheba says, ...->b
is undefined.
I answered the very same question some time ago, here.
C imposes no rule about how much padding is left between 2 consecutive members of a structure.
This is why the implementations define many #pragma directives -- specially to change this behaviour.
So, as the answer of Bathsheba says, ...->b
is undefined.
I answered the very same question some time ago, here.
edited Jan 17 at 15:58
answered Jan 17 at 14:53
alinsoaralinsoar
8,44813149
8,44813149
add a comment |
add a comment |
Pointer punning is not safe. Use real union punning instead.
Assumptions: the struct is properly packed (no padding between the members)
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) result{
int a;
int b;
int c;
int d;
};
union convert{
int arr[4];
struct result res;
};
volatile int arr1[4];
void foo(void)
{
union convert cnv;
memcpy(&cnv, (void *)arr1, sizeof(arr1));
printf("%d %dn", cnv.res.a, cnv.res.b);
}
all modern compilers will optimize out the memcpy
call
https://godbolt.org/z/4qtRIF
.LC0:
.string "%d %dn"
foo:
mov rsi, QWORD PTR arr1[rip]
xor eax, eax
mov rdi, QWORD PTR arr1[rip+8]
mov edi, OFFSET FLAT:.LC0
mov rdx, rsi
sar rdx, 32
jmp printf
Why thevolatile
global?
– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
add a comment |
Pointer punning is not safe. Use real union punning instead.
Assumptions: the struct is properly packed (no padding between the members)
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) result{
int a;
int b;
int c;
int d;
};
union convert{
int arr[4];
struct result res;
};
volatile int arr1[4];
void foo(void)
{
union convert cnv;
memcpy(&cnv, (void *)arr1, sizeof(arr1));
printf("%d %dn", cnv.res.a, cnv.res.b);
}
all modern compilers will optimize out the memcpy
call
https://godbolt.org/z/4qtRIF
.LC0:
.string "%d %dn"
foo:
mov rsi, QWORD PTR arr1[rip]
xor eax, eax
mov rdi, QWORD PTR arr1[rip+8]
mov edi, OFFSET FLAT:.LC0
mov rdx, rsi
sar rdx, 32
jmp printf
Why thevolatile
global?
– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
add a comment |
Pointer punning is not safe. Use real union punning instead.
Assumptions: the struct is properly packed (no padding between the members)
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) result{
int a;
int b;
int c;
int d;
};
union convert{
int arr[4];
struct result res;
};
volatile int arr1[4];
void foo(void)
{
union convert cnv;
memcpy(&cnv, (void *)arr1, sizeof(arr1));
printf("%d %dn", cnv.res.a, cnv.res.b);
}
all modern compilers will optimize out the memcpy
call
https://godbolt.org/z/4qtRIF
.LC0:
.string "%d %dn"
foo:
mov rsi, QWORD PTR arr1[rip]
xor eax, eax
mov rdi, QWORD PTR arr1[rip+8]
mov edi, OFFSET FLAT:.LC0
mov rdx, rsi
sar rdx, 32
jmp printf
Pointer punning is not safe. Use real union punning instead.
Assumptions: the struct is properly packed (no padding between the members)
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) result{
int a;
int b;
int c;
int d;
};
union convert{
int arr[4];
struct result res;
};
volatile int arr1[4];
void foo(void)
{
union convert cnv;
memcpy(&cnv, (void *)arr1, sizeof(arr1));
printf("%d %dn", cnv.res.a, cnv.res.b);
}
all modern compilers will optimize out the memcpy
call
https://godbolt.org/z/4qtRIF
.LC0:
.string "%d %dn"
foo:
mov rsi, QWORD PTR arr1[rip]
xor eax, eax
mov rdi, QWORD PTR arr1[rip+8]
mov edi, OFFSET FLAT:.LC0
mov rdx, rsi
sar rdx, 32
jmp printf
answered Jan 17 at 14:56
P__J__P__J__
10.9k2725
10.9k2725
Why thevolatile
global?
– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
add a comment |
Why thevolatile
global?
– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
Why the
volatile
global?– curiousguy
Jan 18 at 11:30
Why the
volatile
global?– curiousguy
Jan 18 at 11:30
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
Jan 18 at 11:40
I don't follow you.
– curiousguy
Jan 18 at 19:38
I don't follow you.
– curiousguy
Jan 18 at 19:38
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
@curiousguy so you need to read more about the optimizations. Try to remove the volatile and see what will happen. Try yourself that is the only way
– P__J__
Jan 18 at 19:40
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
Actually you are the one who needs to read more.
– curiousguy
Jan 18 at 19:42
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54237976%2fis-this-type-punning-well-defined%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
@StoryTeller I'm sorry, it typing mistake.
– KBlr
Jan 17 at 14:29
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
Jan 17 at 14:30
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
Jan 17 at 14:36
2
@Bathsheba: Darn me and me illiteracy
– AndyG
Jan 17 at 14:37
1
Hmmm, If
static_assert(sizeof(convert.arr) == sizeof(convert.res), "Hmmm");
was added, I think the concern about padding is gone - Code would simply not compile when padding occurred.– chux
Jan 17 at 16:53