嵌套 static_cast 和 const_cast
Nested static_cast and const_cast
我有一个如下所示的系统调用:
int transfer(int handle, int direction, unsigned char *data, int length);
我写了下面两个函数:
int input(int handle, void* data, int length)
{
return transfer(handle, 1, static_cast<unsigned char*>(data), length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, static_cast<unsigned char*>(const_cast<void*>(data)), length);
}
我不喜欢 static_cast
中嵌套的 const_cast
,有没有办法一步完成从 const void*
到 unsigned char*
的转换?
使用 C 风格的转换将生成相同的程序集。 As seen in Compiler Explorer:
//Source #1
int transfer(int handle, int direction, unsigned char *data, int length);
int input(int handle, void* data, int length)
{
return transfer(handle, 1, static_cast<unsigned char*>(data), length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, static_cast<unsigned char*>(const_cast<void*>(data)), length);
}
//Source #2
int transfer(int handle, int direction, unsigned char *data, int length);
int input(int handle, void* data, int length)
{
return transfer(handle, 1, (unsigned char*)data, length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, (unsigned char*)data, length);
}
//Assembly (both)
input(int, void*, int):
mov ecx, edx
mov rdx, rsi
mov esi, 1
jmp transfer(int, int, unsigned char*, int)
output(int, void const*, int):
mov ecx, edx
mov rdx, rsi
xor esi, esi
jmp transfer(int, int, unsigned char*, int)
很明显,只需使用 C 风格的转换就可以解决您的问题。
但是,您不应该使用 C 风格的转换
C++ 强制转换冗长的原因是为了确保您不会犯错误。当维护者看到您的代码时,他们看到 const_cast
和 static_cast
很重要,因为以这种方式编写代码会告知 reader 抛弃 const
-ness指针是有意和期望的行为。代码维护者应该看到这些转换,并假定代码背后有意图,而不必猜测您是否知道直接从 const void*
转换为 unsigned char*
会涉及未定义行为的风险。您的示例可能不包含 UB(因为您指定 transfer
的合同在 direction
为 0 时将 data
视为只读),但重要的是其他任何需要对您的代码进行更改了解您的编码实践的深思熟虑。
您不希望 data
不常量。如果 transfer
试图修改它怎么办?
拥有本地副本会更安全:
#include <cstring>
int output(int handle, const void* data, int length)
{
unsigned char localData[length];
std::memcpy(localData, data, length);
return transfer(handle, 0, localData, length);
}
编辑:通读评论,这就是 Shlublu 的建议...
我有一个如下所示的系统调用:
int transfer(int handle, int direction, unsigned char *data, int length);
我写了下面两个函数:
int input(int handle, void* data, int length)
{
return transfer(handle, 1, static_cast<unsigned char*>(data), length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, static_cast<unsigned char*>(const_cast<void*>(data)), length);
}
我不喜欢 static_cast
中嵌套的 const_cast
,有没有办法一步完成从 const void*
到 unsigned char*
的转换?
使用 C 风格的转换将生成相同的程序集。 As seen in Compiler Explorer:
//Source #1
int transfer(int handle, int direction, unsigned char *data, int length);
int input(int handle, void* data, int length)
{
return transfer(handle, 1, static_cast<unsigned char*>(data), length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, static_cast<unsigned char*>(const_cast<void*>(data)), length);
}
//Source #2
int transfer(int handle, int direction, unsigned char *data, int length);
int input(int handle, void* data, int length)
{
return transfer(handle, 1, (unsigned char*)data, length);
}
int output(int handle, const void* data, int length)
{
return transfer(handle, 0, (unsigned char*)data, length);
}
//Assembly (both)
input(int, void*, int):
mov ecx, edx
mov rdx, rsi
mov esi, 1
jmp transfer(int, int, unsigned char*, int)
output(int, void const*, int):
mov ecx, edx
mov rdx, rsi
xor esi, esi
jmp transfer(int, int, unsigned char*, int)
很明显,只需使用 C 风格的转换就可以解决您的问题。
但是,您不应该使用 C 风格的转换
C++ 强制转换冗长的原因是为了确保您不会犯错误。当维护者看到您的代码时,他们看到 const_cast
和 static_cast
很重要,因为以这种方式编写代码会告知 reader 抛弃 const
-ness指针是有意和期望的行为。代码维护者应该看到这些转换,并假定代码背后有意图,而不必猜测您是否知道直接从 const void*
转换为 unsigned char*
会涉及未定义行为的风险。您的示例可能不包含 UB(因为您指定 transfer
的合同在 direction
为 0 时将 data
视为只读),但重要的是其他任何需要对您的代码进行更改了解您的编码实践的深思熟虑。
您不希望 data
不常量。如果 transfer
试图修改它怎么办?
拥有本地副本会更安全:
#include <cstring>
int output(int handle, const void* data, int length)
{
unsigned char localData[length];
std::memcpy(localData, data, length);
return transfer(handle, 0, localData, length);
}
编辑:通读评论,这就是 Shlublu 的建议...