如何更新具有兼容性的C/C++结构
我struct在历史图书馆中定义了一个遗憾的类型:unsigned char *而不是char*.
struct MyStruct {
unsigned char * myMember;
};
这struct被大量的 C 应用程序使用,并且越来越多地被 C++ 应用程序使用。这些 C++ 应用程序在与 一起使用时会引发错误strlen,例如,强制我们进行强制转换。很多演员。
我想解决这个问题。
但是有一点非常重要:它必须绝对兼容,无需修改,对现有项目没有影响。
我想过制作一个union. 唉,我的变量不能同名。
struct MyStruct {
union {
unsigned char * myMember;
// char * myMember; Obvioulsy, rejected by the compiler.
};
恐怕没有任何明显的解决方案。我错了吗?
我无法更改结构的大小,因为它映射到大小不变的共享内存中。
回答
注意:你不能在 C++ 中解决这个问题,因为严格的 C 也不喜欢unsigned char*。即使使用宽松的 C 编译器设置,您也会得到(gcc 默认设置的示例):
赋值中的指针目标的符号不同 [-Wpointer-sign]|
即使在做一些基本的事情,比如简单的赋值ms.myMember="hello";。
这是一个 C11 解决方案。
struct MyStruct {
union // anonymous union
{
unsigned char * myMember;
char* myCharMember;
};
};
#define myMember myCharMember
测试代码:
struct MyStruct ms;
_Generic(ms.myMember,
char*: puts("I'm a char*"),
unsigned char*: puts("I'm an unsigned char*"));
没有#define和 它会告诉你"I'm an unsigned char*",但是有了#define, "I'm a char*"。
回答
有一个更简单的补救措施。通常,当你对某件事做太多次而感到恼火时,可以简单地通过在函数内做一次那件事来解决:
std::size_t unsigned_strlen(const unsigned char* str) noexcept
{
return std::strlen(reinterpret_cast<const char*>(str));
}
- @AdrianMole Adding functions to `std` namespace is not allowed.
- You'd have to do this for _all_ string handling functions not just strlen. Quite tedious.
回答
There is no way you can make the myMember be a char* or any other type without potentially breaking existing projects, for the simple reason that its type can be deduced
void foo(decltype(MyStruct::myMember));
This will cause ABI issues, the mildest of which is a linker error.
The half measure is to provide a shorthand for the cast
struct MyStruct
{
#ifdef __cplusplus
char* signed_myMember() { return (char*)myMember; }
#endif
};
Fortunately, char is allowed to alias anything in C++, making this legal.