如何更新具有兼容性的 C/C++ 结构

bit*_*kid 16 c c++ compatibility casting

struct在历史图书馆中定义了一个遗憾的类型:unsigned char *而不是char*.

struct MyStruct {

  unsigned char * myMember;
};
Run Code Online (Sandbox Code Playgroud)

struct被大量的 C 应用程序使用,并且越来越多地被 C++ 应用程序使用。这些 C++ 应用程序在与 一起使用时会引发错误strlen,例如,强制我们进行强制转换。很多演员。

我想解决这个问题。

但是有一点非常重要:它必须绝对兼容,无需修改,对现有项目没有影响。

我想过制作一个union. 唉,我的变量不能同名。

struct MyStruct {

  union {
    unsigned char * myMember;
    // char * myMember; Obvioulsy, rejected by the compiler.
};
Run Code Online (Sandbox Code Playgroud)

恐怕没有任何明显的解决方案。我错了吗?

我无法更改结构的大小,因为它映射到大小不变的共享内存中。

Lun*_*din 10

注意:你不能在 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
Run Code Online (Sandbox Code Playgroud)

测试代码:

struct MyStruct ms;  
_Generic(ms.myMember, 
         char*:           puts("I'm a char*"), 
         unsigned char*:  puts("I'm an unsigned char*"));
Run Code Online (Sandbox Code Playgroud)

没有#define和 它会告诉你"I'm an unsigned char*",但是有了#define, "I'm a char*"


eer*_*ika 8

有一个更简单的补救措施。通常,当你对某件事做太多次而感到恼火时,可以简单地通过在函数内做一次那件事来解决:

std::size_t unsigned_strlen(const unsigned char* str) noexcept
{
    return std::strlen(reinterpret_cast<const char*>(str));
}
Run Code Online (Sandbox Code Playgroud)

  • @AdrianMole 不允许向 `std` 命名空间添加函数。 (6认同)
  • 您必须对所有字符串处理函数执行此操作,而不仅仅是 strlen。相当乏味。 (5认同)

Pas*_* By 5

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));
Run Code Online (Sandbox Code Playgroud)

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
};
Run Code Online (Sandbox Code Playgroud)

Fortunately, char is allowed to alias anything in C++, making this legal.


bob*_*bah 2

鉴于您的目标是创建一个完美岛而不是修复世界,您可以从这个旧结构创建一个带有隐式构造函数的适配器,并在“完美岛”代码中使用该适配器。

struct BetterMyStruct {
  char* myMember;
  
  BetterMyStruct(MyStruct const& x): myMember((char*)x.myMember) {
    // any ugly secret hacks you want or need
  }

};

...

size_t better_strlen(BetterMyStruct const& x) {
  // perfect function
  return std::string_view(x.myMember).size();
}

...

better_strlen(MyStruct(...)); // perfect function invocation on imperfect inputs
Run Code Online (Sandbox Code Playgroud)