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

Assuming that there are no alignment problems between the two pointer types (impl-defined), the code is otherwise well-defined. As per the quoted 6.3.2.3 C allows pretty much any form of wild and c...

posted 1y ago by Lundin‭

Answer
#1: Initial revision by user avatar Lundin‭ · 2023-01-20T07:37:21Z (about 1 year ago)
Assuming that there are no alignment problems between the two pointer types (impl-defined), the code is otherwise well-defined. As per the quoted 6.3.2.3 C allows pretty much any form of wild and crazy pointer conversions by means of a cast, as long as you don't actually de-reference the pointer through the wrong type.

As for the original intention of strict pointer aliasing, it was exactly for cases like this where the compiler should be allowed to assume that `double *f` and `int64_t *j` do not alias, especially when the caller is in a different translation unit. But since you overrule all such internal decisions with the explicit cast, the compiler just has to fall in line. And it is fine to convert back to the correct pointer type.

`restrict` is only an optimizer hint to the compiler and in this case of using the same variable for both arguments, the caller would be violating the "restrict contract" between the caller and a `restrict` qualified function. I don't know of any compiler which actually checks for `restrict` violations by the caller.

If you would remove the cast and assignment in the function, then the compiler would still be free to assume that the pointers don't alias even without `restrict`. 

I managed to create a peculiar example with gcc and clang -O3

```c
#include <inttypes.h>
#include <stdio.h>

void
bar(double *f, int64_t * j)
{
    int64_t tmp = *j;
    *f = 1.0;

    if(*j == tmp)
      printf("%"PRIi64 " %"PRIi64 "\n", *j, tmp);
}

int main (void)
{
    int64_t i = 1;

    bar((double *) &i, &i);
    printf("%" PRIi64 "\n", i);
}
```

Output:

```text
1 1
4607182418800017408
```

Apparently the compiler assumes:

- `tmp` holds the value of `*j`
- Thus `tmp` and `*j` have the same value, since `*j` has not been changed.
- Thus print `tmp` twice (why load `*j` from RAM again?).
- Then on the caller side print the actual value of `*j` which may have changed by the function with external linkage.

Without -O3 the `1 1` is never printed.

The same thing happens at -O3 if I change the function to:

```c
void
bar(int64_t*restrict f, int64_t*restrict j)
{
    int64_t tmp = *j;
    *f = 2;

    if(*j == tmp)
      printf("%"PRIi64 " %"PRIi64 "\n", *j, tmp);
}
```

However, if `restrict` is dropped it does not print `1 1` regardless of optimizations.