ç克服走样限制(工会?) [英] C overcoming aliasing restrictions (unions?)
问题描述
假设我有一个范例源文件test.c的,这我编译像这样:
Assume I have a sample source file, test.c, which I am compiling like so:
$ gcc -03 -Wall
test.c的看起来是这样的。
test.c looks something like this ..
/// CMP128(x, y)
//
// arguments
// x - any pointer to an 128-bit int
// y - any pointer to an 128-bit int
//
// returns -1, 0, or 1 if x is less than, equal to, or greater than y
//
#define CMP128(x, y) // magic goes here
// example usages
uint8_t A[16];
uint16_t B[8];
uint32_t C[4];
uint64_t D[2];
struct in6_addr E;
uint8_t* F;
// use CMP128 on any combination of pointers to 128-bit ints, i.e.
CMP128(A, B);
CMP128(&C[0], &D[0]);
CMP128(&E, F);
// and so on
让我们也可以说我接受的限制,如果在两个重叠的指针传递,你会得到不确定的结果。
let's also say I accept the restriction that if you pass in two overlapping pointers, you get undefined results.
我已经试过这样的事情(想象一下这些宏的格式正确用反斜杠转义换行符在每行的结尾)
I've tried something like this (imagine these macros are properly formatted with backslash-escaped newlines at the end of each line)
#define CMP128(x, y) ({
uint64_t* a = (void*)x;
uint64_t* b = (void*)y;
// compare a[0] with b[0], a[1] with b[1]
})
但是当我取消引用宏(A [0]< B [0])我得到提领休息严格走样规则,从海湾合作委员会的错误
but when I dereference a in the macro (a[0] < b[0]) I get "dereferencing breaks strict-aliasing rules" errors from gcc
我原以为你是应该使用工会能够正确引用一个地方在内存中以两种不同的方式,所以接下来我想是这样
I had thought that you were supposed to use unions to properly refer to a single place in memory in two different ways, so next I tried something like
#define CMP128(x, y) ({
union {
typeof(x) a;
typeof(y) b;
uint64_t* c;
} d = { .a = (x) }
, e = { .b = (y) };
// compare d.c[0] with e.c[0], etc
})
除我从大约严格走样规则编译器得到完全相同的错误。
Except that I get the exact same errors from the compiler about strict-aliasing rules.
所以:是有一些方法来做到这一点不打破严格走样,短的实际复印的内存
So: is there some way to do this without breaking strict-aliasing, short of actually COPYING the memory?
( may_alias 犯规次数,它只是允许你绕过严格走样规则)
(may_alias doesnt count, it just allows you to bypass the strict-aliasing rules)
编辑:使用memcmp做到这一点。我上了别名规则赶上了,没想到它。
use memcmp to do this. I got caught up on the aliasing rules and didn't think of it.
推荐答案
作为别名规则是由所谓确定的编译器是正确的
对象(即内存位置)的有效型你所访问,无论任何指针魔术。在这种情况下,类型双关的指针与工会没有比显式类型转换的不同 - 利用中投实际上是preferable为标准并不能保证arbitary指针类型有兼容的重presentations,即您无需再依赖于实现定义的行为。
The compiler is correct as the aliasing rules are determined by the so-called 'effective type' of the object (ie memory location) you're accessing, regardless of any pointer magic. In this case, type-punning the pointers with a union is no different than an explicit cast - using the cast is actually preferable as the standard does not guarantee that arbitary pointer types have compatible representations, ie you're unnecessarily depending on implementation-defined behaviour.
如果要符合标准,则需要将数据复制到新的变量或原始变量的。
If you want to conform to the standard, you need to copy the data to new variables or use a union during the declaration of the original variables.
如果您的128位的整数或者是大端或小端(即非混合端),你也可以使用 memcmp()
(直接或否定的返回值后),或自己做一个逐字节的比较:通过字符类型的指针访问是一个例外走样规则
If your 128-bit integers are either big-endian or little-endian (ie not mixed-endian), you could also use memcmp()
(either directly or after negating the return value) or do a byte-wise comparison yourself: access through pointers of character type is an exception to the aliasing rule.
这篇关于ç克服走样限制(工会?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!