-1

I am trying to call this function

static inline void insert(Buffer *buf, double f, size_t index)
{
   insert_64(buf, *(uint64_t *)&f, index);
}

But, I am getting this error:

error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]

Don't know where I am going wrong.

pavikirthi
  • 1,569
  • 3
  • 17
  • 26
  • 3
    `*(uint64_t *)&f` There. You can't just pretend a pointer to a `float` is pointer to a `uint64_t` and get away with it. – Hatted Rooster Mar 06 '18 at 19:14
  • 1
    Possible duplicate of [Fix for dereferencing type-punned pointer will break strict-aliasing](https://stackoverflow.com/questions/8824622/fix-for-dereferencing-type-punned-pointer-will-break-strict-aliasing) – Fred Larson Mar 06 '18 at 19:15
  • You're doing nothing wrong. It's just against the rules. So turn off the rule. – Lee Daniel Crocker Mar 06 '18 at 19:15
  • The error message should tell you where exactly (file, line number). – melpomene Mar 06 '18 at 19:15
  • 4
    @LeeDanielCrocker Dereferencing that new pointer is UB, OP is _definitely_ doing something wrong. – Hatted Rooster Mar 06 '18 at 19:16
  • 1
    take a look here: [What is the strict aliasing rule?](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – yano Mar 06 '18 at 19:17
  • 1
    @LeeDanielCrocker, as someone whose job it used to be to port widely-used software to niche platforms (when working at an embedded-systems house), I can quite confidently say that the "eff-the-rules" approach is creating misery for others. – Charles Duffy Mar 06 '18 at 19:20
  • @LeeDanielCrocker That attitude has led to a number of bugs in major projects already. :) There's a reason a standard exists, follow it and it's rules or be prepared to have a meaningless program. – Hatted Rooster Mar 06 '18 at 19:20
  • No, that attitude leads to non-portable code. That's not a crime, it's a choice. Portability is a great thing, if you need it. Frankly, if I wanted portability, I wouldn't use C. – Lee Daniel Crocker Mar 06 '18 at 19:23
  • @LeeDanielCrocker By "portability", do you mean the same code still working in the next version of your compiler? Or in another location in your source? – melpomene Mar 06 '18 at 19:26
  • 2
    No, it is not only about portability. Breaking strict aliasing rule along with some optimizations might lead to much funnier stuff. Take a look here: http://blog.qt.io/blog/2011/06/10/type-punning-and-strict-aliasing/ – Eugene Sh. Mar 06 '18 at 19:26
  • 1
    Since C99, use `insert_64(buf, (union { double d; uint64_t u64; }){f}.u64, index);` to avoid breaking strict-aliasing rule. – chux - Reinstate Monica Mar 06 '18 at 19:27
  • @chux Yet I would strongly suggest to break it into few separate statements... – Eugene Sh. Mar 06 '18 at 19:28
  • @LeeDanielCrocker I do now understand about those blue screens on windows from where they are coming from. – Michi Mar 06 '18 at 19:29
  • Yep, things like optimization and alignment are definitely an issue, and programmers should be aware of them. I'm just saying the programmer should be in charge, not the standard. Standards are wonderful guidelines, and you should know the rules before you break them. But if breaking them produces the best code for your job, sobeit. I work on embedded systems that might have as little as 1K of ram. Wasting bytes using memcpy() to avoid type aliasing might not be an option. – Lee Daniel Crocker Mar 06 '18 at 19:30
  • What's "Windows"? Is that a software product of some kind? :-) – Lee Daniel Crocker Mar 06 '18 at 19:32
  • @LeeDanielCrocker I too work with embedded and find code like `memcpy(&x, &f, sizeof(f))` less and less of an issue. As with limited RAM/ROM, to save space, I use optimize compilers that readily take code like `memcpy(&x, &f, sizeof(f))` and emit efficient load-store assembly code per _Analyzability_. Yet with these highly optimized compilers, they more often take advantage of things like AA violations - to my chagrin, so I avoid coding styles that in the past helped and have adopted compliant ones and let the compiler optimize. Yet if stuck with an old compiler, you do what one needs to do. – chux - Reinstate Monica Mar 06 '18 at 19:43
  • @pavikirthi, What C coding standard are you targeting? C 11, C99, earlier? – chux - Reinstate Monica Mar 06 '18 at 19:45
  • @chux I am using c99 and again I am trying to use it on low memory devices, so does memcpy makes sense? – pavikirthi Mar 06 '18 at 19:49
  • @pavikirthi [does memcpy makes sense?](https://stackoverflow.com/questions/49138322/werror-strict-aliasing-error-in-c/49139020#comment85282788_49138322) It _can_ make sense, Was the compiled code efficient? – chux - Reinstate Monica Mar 06 '18 at 20:01
  • @chux, I am running the code on off target, so I haven't flashed the code onto the device yet, so right now its compiling fine. – pavikirthi Mar 06 '18 at 20:07

2 Answers2

1

As was mentioned in the comments, attempting to convert a pointer to one type into a pointer of another type breaks the strict aliasing rule. You can get around this by using memcpy to copy bytes from one type to another:

uint64_t x;
memcpy(&x, &f, sizeof(f));

Note that what x contains depends on the implementation, i.e. what is the representation of double, is the system big-endian or little-endian, is a double 64 bits, etc.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

Don't know where I am going wrong.

*(uint64_t *)&f breaks the strict-aliasing rules. See Fix for dereferencing type-punned pointer will break strict-aliasing

To fix, use a memcpy() as well answered by @dbush or a union. A union copes with the strict-aliasing rules.

void insert2(Buffer *buf, double f, size_t index) {
  union { 
    double d; 
    uint64_t u64;
  } u = { f };
  insert_64(buf, u.u64, index);
}

or also use a compound literal (available since C99)

void insert3(Buffer *buf, double f, size_t index) {
  //             v-----------------------------------------v   compound literal        
  insert_64(buf, (union { double d; uint64_t u64; }){.d = f}.u64, index);
}

With C11, I would add the below for future assessment of correctness.

_Static_assert(sizeof (double) == sizeof (uint64_t), "Unexpected sizes");

Note: rare platforms have differing endian per integer and FP types.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256