3

I have already read a number of questions about this warning (Dereferencing type-punned pointer will break strict-aliasing rules, Dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing], What is the strict aliasing rule?, "dereferencing type-punned pointer will break strict-aliasing rules" warning and others) and got totally confused about my warning.

So I have a struct:

typedef struct {
    unsigned char precision;
    unsigned char scale;
    unsigned char array[33];
} DBNUMERIC;

This struct is filled by FreeTDS library when retrieving data from MS SQL Server. I know that starting from array[1] there is 64-bit integral number (in big-endian) and I want to get it. I use the following code:

int64_t result = 0;
result = be64toh(*((decltype(result)*)(numeric.array + 1)));

But GCC gives me the warning dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]. But if I use the code:

int64_t result = 0;
decltype(result)* temp_ptr = (decltype(result)*)(numeric.array + 1);
decltype(result) temp = *temp_ptr;
result = be64toh(temp);

there are no warnings about violating strict-aliasing rules. I don't think that this code differs from the original, therefore I am confused. How can I convert 8 bytes from the array to a int64_t variable?

Community
  • 1
  • 1
user2717575
  • 369
  • 7
  • 16
  • The [gcc strict aliasing warnings are not perfect](http://stackoverflow.com/a/25118277/1708801) and so are subject to false positives and false negatives depending on the setting. – Shafik Yaghmour Oct 30 '15 at 11:32
  • 1
    Just use memcpy to type-pun see [this](http://blog.regehr.org/archives/959). – Shafik Yaghmour Oct 30 '15 at 11:52
  • [Not reproducible here](http://coliru.stacked-crooked.com/a/235334c24de643ee). Pointers to `char` and variants are explicitly exempt from strict aliasing rules, so a warning would not be justified. – n. m. could be an AI Oct 30 '15 at 11:53
  • 1
    @n.m. you have it backwards, `char*` is always allowed to alias not vice-versa. These warnings are version and optimization sensitive see [this live session](http://melpon.org/wandbox/permlink/DL11c37348yCKQHY). – Shafik Yaghmour Oct 30 '15 at 12:06
  • 1
    If your hardware has alignment restrictions on `int64_t`, your `decltype(result) temp = *temp_ptr;` will likely result in a `SIGBUS`. @ShafikYaghmour recommendation to use `memcpy()` is the proper way to access the data as an `int64_t`. – Andrew Henle Oct 30 '15 at 12:13
  • @ShafikYaghmour that's what I'm saying, not sure what exactly is backwards. – n. m. could be an AI Oct 30 '15 at 17:23
  • @n.m. you said *warning would not be justified* but it is definitely justified in this case. – Shafik Yaghmour Oct 30 '15 at 17:41
  • @ShafikYaghmour OK I see what you mean. – n. m. could be an AI Oct 30 '15 at 18:22
  • @n.m. great, for reference you can see [my answer here](http://stackoverflow.com/a/20956250/1708801) for the relevant details. – Shafik Yaghmour Oct 30 '15 at 18:40

1 Answers1

5

Both of your cases violate the strict aliasing rules. gcc's strict-aliasing warnings are subject to false negatives and false positives depending on the warning and optimization levels.

If you want to type-pun in a way not allowed by the strict aliasing rules then you should just use std::memcpy:

std::memcpy(&result, numeric.array+1, sizeof(int64_t ));

We can see from the following sources; this article Type Punning, Strict Aliasing, and Optimization and the std-dicussion conversation on type punning and unions I quote in my answer here tell us that the compiler should be smart enough to optimize for the use of memcpy to generate efficient code.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740