Issue
In C:
struct __attribute__((scalar_storage_order("big-endian"))) test_struct{
int a;
int b;
int c;
};
struct test_struct test1 = {1,1,1};
struct test_struct test2[3] = {{1,1,1},{1,1,1},{1,1,1}};
void func1(int *arg);
void func2(struct test_struct *arg);
int main()
{
func1(&test1.a);
func2(&test2[1]);
return 0;
}
void func1(int *arg){};
void func2(struct test_struct *arg){}
The call to func1 results in the GCC (Linux) error "cannot take address of scalar with reverse storage order" while the call to func2 compiles and executes as expected.
This is just a simple example that demonstrates the issue I've encountered in a much larger code base that can't be posted for proprietary reasons.
The code base is dual target where the targets differ in endianness, hence the scalar_storage_order modification on the big-endian target version. GCC version 8.5.0
I'm struggling to understand how scalar_storage_order works 'under the hood', why can I pass the address of a struct that contains reverse order scalar variable, but I can't pass the address of the reverse scalar variable itself? How does memory get organized to create these 2 conditions?
Solution
The Wikipedia page about endianness tells you some background.
Anyway, in simple words and your case, endianness means the order to store a value that spans several memory cells, here multiple bytes of int
s.
This is a simple test program, probably non-conforming to the standard:
#include <stdio.h>
static void dump(unsigned char *p, size_t l) {
while (l > 0) {
printf("%02X", *p);
p++;
l--;
}
puts("");
}
int main(void) {
struct __attribute__((scalar_storage_order("big-endian"))) {
int v;
} be = { 0x12345678 };
struct __attribute__((scalar_storage_order("little-endian"))) {
int v;
} le = { 0x12345678 };
dump((unsigned char *)&be, sizeof be);
dump((unsigned char *)&le, sizeof le);
return 0;
}
On my system (Windows 10 with an older MinGW) this program prints:
12345678
78563412
So the error reminds you to check the endianness of the referenced value. And as you see from the experiment, it tries to stop you from mis-interpretation. test1.a
is a value in reverse endianness to the default int
.
Note: This attribute is supported by GCC only for structures and unions and has an effect only on scalar types and arrays there of, and not for all targets.
Answered By - the busybee Answer Checked By - Robin (WPSolving Admin)