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
2 days ago
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
1
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
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
2 days ago
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 2 days ago
AndyG
26.3k76995
26.3k76995
asked 2 days ago
KBlrKBlr
1699
1699
@StoryTeller I'm sorry, it typing mistake.
– KBlr
2 days ago
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
1
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
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
2 days ago
add a comment |
@StoryTeller I'm sorry, it typing mistake.
– KBlr
2 days ago
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
1
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
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
2 days ago
@StoryTeller I'm sorry, it typing mistake.
– KBlr
2 days ago
@StoryTeller I'm sorry, it typing mistake.
– KBlr
2 days ago
2
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
1
1
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
|
show 5 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
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
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
2 days ago
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
|
show 5 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
2 days ago
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
|
show 5 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 2 days ago
BathshebaBathsheba
176k27252376
176k27252376
1
@KBlr: Yep! Just not portable
– AndyG
2 days ago
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
|
show 5 more comments
1
@KBlr: Yep! Just not portable
– AndyG
2 days ago
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.
– Eric Postpischil
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
1
1
@KBlr: Yep! Just not portable
– AndyG
2 days ago
@KBlr: Yep! Just not portable
– AndyG
2 days ago
3
3
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.– Eric Postpischil
2 days ago
pointer->res.a
accesses an object (arr1
) through an lvalue (pointer->res
) in violation of C 2018 6.5 7.– Eric Postpischil
2 days ago
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
2 days ago
@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
2 days ago
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
2 days ago
@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
2 days ago
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
2 days ago
@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
2 days ago
|
show 5 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 2 days ago
answered 2 days ago
chuxchux
81.7k871148
81.7k871148
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 2 days ago
answered 2 days ago
alinsoaralinsoar
8,12613047
8,12613047
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
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
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
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
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 2 days ago
P__J__P__J__
9,6592723
9,6592723
Why thevolatile
global?
– curiousguy
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
add a comment |
Why thevolatile
global?
– curiousguy
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
Why the
volatile
global?– curiousguy
yesterday
Why the
volatile
global?– curiousguy
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
to prevent optimizing it out. The example is trivial and the compiler will otherwise just reduce it to the single const assignment.
– P__J__
yesterday
I don't follow you.
– curiousguy
yesterday
I don't follow you.
– curiousguy
yesterday
@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__
yesterday
@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__
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
Actually you are the one who needs to read more.
– curiousguy
yesterday
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
2 days ago
2
Id you can assure no paddign in the structure - it is safe at list with gcc
– P__J__
2 days ago
@AndyG; You're correct on the first point, but on the second, doesn't {1,2,3,5} initialise the array?
– Bathsheba
2 days ago
1
@Bathsheba: Darn me and me illiteracy
– AndyG
2 days ago
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
2 days ago