不允许将 'const unsigned char *const *' 转换为 'const char *const *' 的 static_cast 操作。

6
我遇到的问题是编译器拒绝将我的无符号字符指针转换为有符号字符指针。我曾经使用static_cast来转换符号,所以有点困惑。后来我进行了一些调查研究(虽然不是非常深入,只是简单了解了一下!),即使现在我明白了通过static_cast防止指针类型转换正是它比传统的替代方案更安全和更好的原因(这些替代方案可能会引起实现定义行为或未定义行为),但我仍然不确定我应该为我的情况做什么。
我这里有一个调用OpenGL API函数的签名。
void glShaderSource(
    GLuint shader, GLsizei count, const GLchar **string, const GLint *length
);

我最近更改了文件读取器API,现在不再返回char *类型的从文件读取的数据,而是使用unsigned char *。我认为这种更改并非错误,因为即使它可能是ASCII数据,无符号字符仍然可以更好地处理原始数据,事实上void *在这方面可能更清晰。

当然,我会将此指针的地址作为第三个参数传递给glShaderSource

我想这样做C风格的强制转换到GLchar **应该是安全的,实际上这可能是此情况下的标准答案。使用reinterpret_cast只是多余的操作,但确实只有很少的量。

但是我想了解一下在这种情况下应该考虑什么。为什么我能够忽略这里涉及的字符的符号?难道仅仅因为我不希望编写任何字符高位设置为1的着色器吗?

如果我遇到了带有有符号/无符号整数的情况,并且确实存在将虚假的负整数值解释为大正整数值的严重后果,那么我该如何编写代码来尝试保持“安全”?

我的直觉告诉我,这显然是不可能的,除非实现可以直接检查数据而不是传递指针,因此,在此情况下是否没有办法恢复static_cast的安全性,因为我被迫使用指针。


1
你有什么问题?为什么在p是一个char *的情况下,不能写static_cast<unsigned char *>(p)?这不仅仅是从有符号转换为无符号或反之,而是对指针所指向的内容进行重新解释 - Praetorian
1
那么您的意思是我正在执行一个真正的重新解释操作,因此使用reinterpret_cast是实际上正确的事情吗? - Steven Lu
@StevenLu 我有所怀疑,但当你说“难道我不应该期望编写一个设置了高位的着色器吗?”时,你会理解我的困惑。已经注意到了。 - WhozCraig
是的,对不起,我总是写一堵墙的文字。基本上,我正在尝试弄清楚何时应该使用哪种类型的转换,但你知道吗,这个问题已经得到了回答!就在这个网站上! - Steven Lu
@doc,不,我宁愿保持我的文件读取器逻辑,这样对我来说最有意义。我认为它最初是实现为 char 的,因为当时我将其与某些期望 char 的东西一起使用。但是,正如你所说,尝试使用带符号的 char 类型进行推理和算术运算是愚蠢的,因此我更喜欢在自己的 API 中将其设置为无符号。对于这种类型的情况,如果必须要,我会重新解释转换...该死,我已经忘记了今天我将它改为 unsigned char 的真正原因。可能不是什么非常重要的事情。 - Steven Lu
显示剩余6条评论
2个回答

11
你需要使用 reinterpret_cast 来转换 char *unsigned char * 之间的类型(带或不带 const)。这是因为你正在将存储为一种类型的位视为另一种类型的位,而 static_cast 用于进行值转换。
正如 WhozCraig 指出的,将 char **unsigned char ** 之间转换实际上是将一个指针别名为另一个指针类型(因此也需要 reinterpret_cast)。
理论上这可能会有问题,但在实际考虑中(依我之见),为支持所有可能性所需的工作量过于麻烦。实际上,你可以假设将 char 别名为 unsigned char 与值转换给出相同的结果,对于这两种指针类型也是如此。

1
正确,但重新解释的不是那些类型。还有一个额外的间接层(这并不改变重新解释的需求)。 - WhozCraig
因此,虽然这在技术上是实现定义的行为,但我们可以相当有信心,直到我将其移植到与我们已经使用了很长时间的架构非常不同的架构之前,我可以依赖于这种预期的行为。 - Steven Lu
1
@StevenLu:你可以打赌这样的架构不会有OpenGL实现。 - Dietrich Epp
这也触及到了我的问题的核心,那就是,我能用比reinterpret_cast更小的锤子吗?我恐怕不能。C风格的转换更糟糕! - Steven Lu
@StevenLu,老实说,我真的看不出有什么针对这个问题的简单解决方案,因为你肯定有不同的基本指针类型。当然,到处使用GLchar可能是一个选择,但是...很糟糕。 - WhozCraig
显示剩余5条评论

1
如果您使用void*中间变量,完全可以使用static_cast完成转换:
unsigned char* src = ...;  // your input
char* srcChar = static_cast<char*>(static_cast<void*>(src));
glShaderSource(..., &src, ...);

我不会说它比reinterpret_cast更好,但至少它表明reinterpret_cast并非绝对必要。


注意:如果在特定的实现中reinterpret_cast无法工作,则此方法也无法工作。 - M.M
这有点像巫术。除非它确实带来了一些实际的好处,否则最好不要使用它。但是,这确实是一个很棒的技巧。 - Steven Lu
@StevenLu 好吧,你要求使用 static_cast 解决方案。;) 虽然我不认为这很漂亮,但我认为有趣的是,static_cast 大多被认为比 reinterpret_cast 更安全,但在这种情况下,你可以使用 static_cast 来完成大多数人会使用 reinterpret_cast 的相同操作。 - Reto Koradi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接