Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

71%
+3 −0
Q&A Strict aliasing rules and function boundaries

Let's analyze this code, assuming an architecture where the alignment of int64_t is the same as that of double: void bar(double *f, int64_t *j) { *(int64_t *)f = *j; } void foo(void) ...

1 answer  ·  posted 1y ago by alx‭  ·  edited 1y ago by Lundin‭

#11: Post edited by user avatar Lundin‭ · 2023-01-20T07:40:22Z (about 1 year ago)
Typo
  • Let's analyze this code, assuming an architecture where the alignment of `int64_t` is the same as that of `double`:
  • ```c
  • void
  • bar(double *f, int64_t *j)
  • {
  • *(int64_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int64_t i = 1;
  • bar((double *) &i, &i);
  • }
  • ```
  • - The object is of type `int64_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Does this code have Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
  • Let's analyze this code, assuming an architecture where the alignment of `int64_t` is the same as that of `double`:
  • ```c
  • void
  • bar(double *f, int64_t *j)
  • {
  • *(int64_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int64_t i = 1;
  • bar((double *) &i, &i);
  • }
  • ```
  • - The object is of type `int64_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only see the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Does this code have Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
#10: Post edited by user avatar alx‭ · 2023-01-20T02:20:12Z (about 1 year ago)
#9: Post edited by user avatar alx‭ · 2023-01-20T00:19:21Z (about 1 year ago)
Use wider types, which will more-likely show atomicity problems
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Does this code have Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
  • Let's analyze this code, assuming an architecture where the alignment of `int64_t` is the same as that of `double`:
  • ```c
  • void
  • bar(double *f, int64_t *j)
  • {
  • *(int64_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int64_t i = 1;
  • bar((double *) &i, &i);
  • }
  • ```
  • - The object is of type `int64_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Does this code have Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
#8: Post edited by user avatar alx‭ · 2023-01-20T00:13:19Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Does this code have Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
#7: Post edited by user avatar alx‭ · 2023-01-20T00:10:03Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness in `bar()` by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
#6: Post edited by user avatar alx‭ · 2023-01-20T00:09:36Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • To be clear, there are two doubts in that code:
  • - Is there an implicit `restrict`ness by the fact that the pointers are pointers to incompatible types, even if I didn't use the qualifier?
  • - Is it valid to convert a pointer back to its real type before dereferencing, or is that information lost in the function boundary?
#5: Post edited by user avatar alx‭ · 2023-01-20T00:04:51Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i = 1;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
#4: Post edited by user avatar alx‭ · 2023-01-20T00:04:24Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, &i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
#3: Post edited by user avatar alx‭ · 2023-01-20T00:03:35Z (about 1 year ago)
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` (which I didn't use on purpose) and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
#2: Post edited by user avatar alx‭ · 2023-01-20T00:03:07Z (about 1 year ago)
  • Let's analyze this function, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
  • Let's analyze this code, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:
  • ```c
  • void
  • bar(float *f, int32_t *j)
  • {
  • *(int32_t *)f = *j;
  • }
  • void
  • foo(void)
  • {
  • int32_t i;
  • bar((float *) &i, i);
  • }
  • ```
  • - The object is of type `int32_t`.
  • - The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
  • <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
  • - It's converted back to the actual type of the object, before it's dereferenced.
  • However, how does this play with `restrict` and the strict aliasing rules, and assumptions that compilers may make?
  • Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters. With that information, it doesn't know that the real type is correctly accessed, so what can it do? Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?
  • Is this code snippet Defined Behavior?
#1: Initial revision by user avatar alx‭ · 2023-01-20T00:02:49Z (about 1 year ago)
Strict aliasing rules and function boundaries
Let's analyze this function, assuming an architecture where the alignment of `int32_t` is the same as that of `float`:

```c
void
bar(float *f, int32_t *j)
{
    *(int32_t *)f = *j;
}

void
foo(void)
{
    int32_t i;

    bar((float *) &i, i);
}
```

-  The object is of type `int32_t`.
-  The pointer is stored as a pointer to a different object type, but that's allowed by C11::6.3.2.3/7:
   <https://port70.net/%7Ensz/c/c11/n1570.html#6.3.2.3p7>
-  It's converted back to the actual type of the object, before it's dereferenced.

However, how does this play with `restrict` and the strict aliasing rules, and assumptions that compilers may make?

Assuming that `bar()` is defined in a different Translation Unit, the compiler will only wee the parameters.  With that information, it doesn't know that the real type is correctly accessed, so what can it do?  Also, AFAIK, compilers interpret this function prototype so that `f` and `j` can not alias, don't they?

Is this code snippet Defined Behavior?