2016-09-29 58 views
3

我与这个庞大的开源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)

+2

你可以命名图书馆吗? – 2501

+0

@ 2501它是[mupdf](http://mupdf.com/) – Cody

+1

你可以在实际的源代码中发布任何链接到这样的例子吗? – 2501

回答

3

所呈现的两种替代方法中的每一种都涉及通过转换将一种类型的指针转​​换为不同的指针类型。这是允许的,包括在C89中。在原始代码中,转换的指针被明确解除引用;在修改的代码中,假定指针将在其他地方解除引用。在这些方面,这两种变化执行完全相同种类的(允许的)行为。

有一个技术差别,但是:第一替换导致char *类型的值经由unsigned char *类型的左值要被访问时被读取初始化表达式的值,以便被分配给str2。在标准的这个术语中,这两个不是“兼容类型”,后者也不是与前者相对应的无符号类型(指针本身没有签名),也不是后者是字符类型或不同版本的前者或工会类型。因此访问违反了俗称为“严格别名规则”的标准规定。

第二种选择还转换不兼容的指针类型之间,但是随后的访问它提供用于(并且第一替代还提供)由严格别名规则是允许的,这既是因为字符类型可以别名任何东西,因为unsigned char是对应于char的无符号类型,并且允许在这样的对应类型之间混叠。

实际上,任何生产就绪的编译器都不可能对原始代码执行任何操作,而不是显然期望的操作,但是修改后的代码既清晰又更正确。

+1

将'char **'强制转换为'unsigned char **'是一种严格的别名冲突,因为严格别名规则只允许'char *'类型来混淆所有内容?我认为签名对于严格的别名并不重要。 – yano

+1

@ yano,演员本身不是违规行为,而且签名不直接是问题。当访问'*(unsigned char **)&str'的​​值时,违规来了,因为该表达式是'unsigned char *'类型的左值,而它指定的对象的有效类型实际上是'char *'。字符类型允许别名,但不是字符类型,它们是(不兼容的)指针类型。此外,对方也不允许签名或无符号类型。 –

+0

我需要再读约10次。谢谢。 – yano

2

没有理由像这样施放。它的选择问题。在

unsigned char *str2 = *(unsigned char **) &str; 

情况下,有一个不必要的非关联化来获得字符的地址s点。

使用

unsigned char *str2 = (unsigned char *)str; 

看上去干净给我。

+1

第一个是未定义的行为(正如John Bollinger的回答所解释的) –

+0

@ M.M谢谢。我以前没有注意到。将删除这个答案。 – haccks