我正在使用这个大型开源C库,我经常在类型之间找到类似的转换:
char *str;
//some code
unsigned char *str2 = *(unsigned char **) &str;
我玩过它,当我改变它看起来像
unsigned char *str2 = (unsigned char *) str;
它似乎没有问题。请注意,这些强制转换在整个代码中都很常见,用于除unsigned char之外的许多类型。
是否有理由通过引用和解除引用来进行此类投射?
修改:我不知道它是否相关,但此代码应符合C89标准。
编辑2:一些具体示例
void *q = *(void **)(&p[i]);
发现于:memento.c(第1122行)
unsigned int rgba = *((unsigned int *)color);
发现于:draw-paint.c(第332行)
return cbz_strnatcmp(*(const char **)a, *(const char **)b);
//both parameters are expected to be const char*
发现于:mucbz.c(第73行)
答案 0 :(得分:3)
所提出的两个备选方案中的每一个都涉及通过强制转换将一种类型的指针转换为不同的指针类型。这是允许的,包括在C89中。在原始代码中,转换的指针被明确地解除引用;在修订后的代码中,假设指针将在别处被解引用。在这些方面,这两种变体执行完全相同的(允许)行为。
然而,有一个技术差异:当读取初始化表达式的值时,第一个替代方法会通过类型char *
的左值访问类型unsigned char *
的值,以便分配给str2
。这两个不是标准意义上的“兼容类型”,后者也不是对应于前者的无符号类型(指针本身没有签名),后者也不是字符类型或不同资格的版本前者,或联盟类型。因此,访问违反了通常称为“严格别名规则”的标准规定。
第二种替代方法也可以在不兼容的指针类型之间进行转换,但是严格的别名规则允许它提供的后续访问(以及第一种替代方案也提供),因为字符类型可以为任何内容添加别名,并且因为{{ 1}}是与unsigned char
对应的无符号类型,允许在这些相应类型之间使用别名。
在实践中,任何生产就绪的编译器都不可能对原始代码执行任何操作,而不是显而易见的,但是修改后的代码更清晰,更正确。
答案 1 :(得分:2)
没有理由这样投。它的选择问题。在
的情况下unsigned char *str2 = *(unsigned char **) &str;
有一个不必要的解除引用来获取字符s
的地址指向。
使用
unsigned char *str2 = (unsigned char *)str;
看起来很干净。