那些日子我一直在阅读reinterpret_cast<>
以及如何使用它(并在大多数情况下避免使用它)。
虽然我了解使用reinterpret_cast<>
进行投射,比如说unsigned char*
到char*
是实现已定义(因此非便携式 em>)似乎没有其他办法让有效地将一个转换为另一个。
假设我使用处理unsigned char*
的库来处理某些计算。 Internaly,我已经使用char*
来存储我的数据(我不能改变它,因为如果我这样做会杀死小狗)。
我会做类似的事情:
char* mydata = getMyDataSomewhere();
size_t mydatalen = getMyDataLength();
// We use it here
// processData() takes a unsigned char*
void processData(reinterpret_cast<unsigned char*>(mydata), mydatalen);
// I could have done this:
void processData((unsigned char*)mydata, mydatalen);
// But it would have resulted in a similar call I guess ?
如果我希望我的代码具有高度可移植性,似乎除了先复制数据之外别无选择。类似的东西:
char* mydata = getMyDataSomewhere();
size_t mydatalen = getMyDataLength();
unsigned char* mydata_copy = new unsigned char[mydatalen];
for (size_t i = 0; i < mydatalen; ++i)
mydata_copy[i] = static_cast<unsigned char>(mydata[i]);
void processData(mydata_copy, mydatalen);
当然,这是非常不理想的,我甚至不确定它比第一种解决方案更便携。
所以问题是,在这种情况下你会做些什么来获得高度可移植的代码?
答案 0 :(得分:6)
便携式是一种实践问题。因此,reinterpret_cast
用于char*
和unsigned char*
之间转换的具体用法是可移植的。reinterpret_cast
但是我仍然会将这种用法包含在一对函数中,而不是直接在每个地方执行reinterpret_cast
。
使用几乎所有瑕疵(包括关于{{1}}的有限保证)的语言支持效率的语言时,不要过分介绍低效率。
这将违背语言的精神,同时坚持这封信。
干杯&amp;第h
答案 1 :(得分:2)
char和unsigned char类型之间的区别仅仅是数据语义。这仅影响编译器对任一类型的数据元素执行算术的方式。 char类型向编译器发出信号,表示高位的值将被解释为负数,因此编译器应执行二进制补码运算。由于这是两种类型之间的唯一区别,我无法想象reinterpret_cast <unsigned char*> (mydata)
生成与(unsigned char*) mydata
不同的输出的情况。此外,如果您只是通知编译器数据语义的变化,即从有符号算术切换到无符号算术,则没有理由复制数据。
编辑:虽然从实际角度来看上述情况属实,但我应该注意到C ++标准规定char,unsigned char和sign char是三种不同的数据类型。 §3.9.1.1:
声明为字符(char)的对象应足够大以存储 实现的基本字符集的任何成员。如果是一个角色 从这个集合中存储一个字符对象的积分值 该角色对象等于单个字符的值 字符的字面形式。它是实现定义的 char对象可以保存负值。字符可以是明确的 声明未签名或签名。普通字符,签名字符和未签名 char是三种不同的类型,统称为窄字符 类型。 char,签名字符和unsigned char占用相同的字符 存储量并具有相同的对齐要求(3.11); 也就是说,它们具有相同的对象表示。对于狭窄 字符类型,对象表示的所有位都参与 价值表示。对于无符号窄字符类型,全部 值表示的可能位模式表示数字。 这些要求不适用于其他类型。在任何特定的 实现时,普通的char对象可以采用相同的值 作为签名字符或未签名字符;哪一个是 实现定义的。
答案 2 :(得分:1)
与演员一起去,实践中没问题。
我只想补充一点:
for (size_t i = 0; i < mydatalen; ++i)
mydata_copy[i] = static_cast<unsigned char>(mydata[i]);
虽然不是未定义的行为,但可以在没有2补码算术的机器上更改字符串的内容。反过来就是未定义的行为。
答案 3 :(得分:1)
对于C兼容性,unsigned char*
和char*
类型具有额外的限制。理由是像memcpy()
这样的函数必须工作,这限制了编译器的自由。 (unsigned char*) &foo
仍然必须指向对象foo。因此,请不要担心这种特殊情况。