【问题标题】:How readily do unterminated char arrays in C++?C++ 中未终止的 char 数组有多容易?
【发布时间】:2014-12-24 03:47:30
【问题描述】:

很抱歉,如果这可以通过 Google 解决 - 我找不到任何东西。

char foo[4] = "abcd";

在 C++ 中无效(由于需要 '\0' 终止符),但 IIRC 在 C 中有效——对吗?

我有一组结构,其中包含大量“固定长度”字符字段,这些字段将被空白填充,而不是 '\0' 终止。我希望能够进行通常的结构初始化——你知道

mystruct bar = {17, "abcd", 0x18, "widget  ", ...

但我不能在 C++ 中做到这一点。我想一种解决方案是将所有像这样的初始化结构放入他们自己的C(不是++)源模块中。我试图避免的丑陋、费力的解决方案是

mystruct bar = {17, {'a', 'b', 'c', 'd'}, 0x18, {'w', 'i', 'd', 'g', 'e', 't', ' ', ' '}, ...

有没有好的 C++ 解决方案?一个聪明的宏可以有效地让“abcd”成为没有'\0'终止符的char[4]?

谢谢, 查尔斯

【问题讨论】:

  • @juanchopanza C++ is stricter on this
  • 为什么不std::string
  • 不应该是char foo[5] = "abcd";在你的例子中?
  • @IlyaKobelevskiy 不,在示例中它是“正确的”。

标签: c++ arrays struct char terminator


【解决方案1】:

为结构提供一个构造函数,该构造函数接受大小大于所需大小 1 的 char 数组,并在复制它们时忽略终止字符。

bar::bar(int, char const(&)[5], int, char const(&)[9], ...)

或者,您可以根据您的文档设置参数char const* 并信任用户传递正确大小的数组。如果您不想或不能向结构添加任何内容,则只需创建一个具有相同参数并返回一个的函数(RVO 应该消除额外的复制)。

【讨论】:

    【解决方案2】:

    你可以使用一个宏来完成这项工作:

    #define MACRO_GET_1(str, i) \
        (sizeof(str) > (i) ? str[(i)] : 0)
    
    #define MACRO_GET_4(str, i) \
        MACRO_GET_1(str, i+0),  \
        MACRO_GET_1(str, i+1),  \
        MACRO_GET_1(str, i+2),  \
        MACRO_GET_1(str, i+3)
    
    #define MACRO_GET_STR(str) MACRO_GET_4(str, 0)
    
    struct mystruct {
        char foo[4];
    };
    
    int main() {
        mystruct obj{ MACRO_GET_STR("abcd") };
        const char* str = "abcd";
        std::cout << memcmp(obj.foo, str, 4); // 0
    
        return 0;
    }
    

    Example

    此代码基于this solution,并且也很容易扩展。

    无论如何,有一个proposal some time ago 可能永远不会达到标准。有一些补丁允许将字符串文字转换为可变字符包。

    【讨论】:

    • 谢谢!那应该这样做。大多数有问题的数组长度为 8 个字符或其他一些“标准”大小,所以我需要 3 或 4 个这样的宏——剩下的我可以用丑陋的方式来做。
    • 您确定 sizeof() 会按照您在第一个宏中的预期工作吗?我想空白填充而不是零填充结果,所以我将其更改为 sizeof(str) >= (i) ? str[(i)] : ' ' 及其几个变体。无论我做什么,结果数组都是零填充的。我的心智模型是表达式始终为真,并且对于所有 i
    • 我想你将不得不使用尺寸来避免零填充,如果这是不可取的
    • 确认:sizeof() 不适用于大多数编译器的宏:stackoverflow.com/questions/4079243/…
    • 您的字符串文字是否允许为 constexpr?如果是这样,C++11 可能会对此有所帮助
    【解决方案3】:

    我认为它将作为一个 uint8 数组(或任何你的编译器支持的)工作。只是永远不要认为它是一个字符串,因为它不是。分配一个额外的字符并初始化为零(通常是自动的)要安全得多。最好还是使用 STL 组件,除非有很好的理由去做其他事情。

    C++ 不是 C。在 C++ 中,编译器试图保证你的安全。在 C 中,这完全是您自己的监视。

    【讨论】:

    • 我喜欢 STL,也喜欢 C++。那里没问题。在这种特殊情况下,我有大量外部固定的“记录格式”强加给我,它们充满了这种 char 数组。我需要在代码中构建一些用于测试目的。我正在寻找一种巧妙的方法。
    • 我的沙箱但不是我的最终平台是 MS VS C++。至少在那里,UINT8 只是 unsigned char 的宏,没有任何区别。编译器似乎有一个本机类型 __int8 但它没有改进。
    • 您可以考虑在导入时或任何时候添加终止 null,因为数组中的额外字符会这样做。您的内部表示不受外部表示的约束。
    猜你喜欢
    • 2012-04-20
    • 2012-01-10
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多