【问题标题】:Is it safe to pass std::string to C style APIs?将 std::string 传递给 C 风格的 API 是否安全?
【发布时间】:2013-05-07 17:44:51
【问题描述】:

将 std::vector 传递给 C API 是定义明确的,因为 std::vector 是连续的:

std::vector<char> myArray(arraySize);
cStyleAPI(&myArray[0], arraySize);

以相同的方式将 std::string 传递给 C API 是否安全?标准 C++03 中是否有任何保证 std::string 是连续的,并且在这种情况下与 std::vector 的工作方式相同?

【问题讨论】:

    标签: c++ c string


    【解决方案1】:

    如果 C API 函数需要对 std::string 的内容进行只读访问,则使用 std::string::c_str() 成员函数来传递字符串。这保证是一个空终止的字符串。

    如果您打算使用std::string 作为out 参数,C++03 不保证存储的字符串在内存中是连续的,但 C++11 可以。后者可以通过operator[]修改字符串,只要你don't modify the terminating NULL character即可。

    【讨论】:

    • c_str() 返回一个 const char *,我需要能够将输出接收到字符串中。不使用 const_cast 和 c_str() 可以这样做吗?
    • @masrtis 不,它仍然不是,但是你为什么不使用char buf[BUFSIZE]
    • @masrtis 好吧,实际上在最合理的实现上?是的!但理论上有标准保证?绝对不是!
    • @Praetorian:只要不违反const_cast 规则并且编译器知道它正在被丢弃(副作用)。
    • @Joel 我从来没有说过你应该这样做。第一部分是在我意识到 OP 打算将字符串用作 out 参数之前。第二句说你应该使用operator[] 来修改字符串。我已经更新了答案以明确。
    【解决方案2】:

    所以,我知道这已经得到了回答,但是我在 Praetorian 的回答中看到了您的评论:

    这是一个 OpenGL 驱动程序错误,导致返回值 最大长度字符串被破坏。看 https://forums.geforce.com/default/topic/531732/glgetactiveattrib-invalid/。 glGetActiveAttrib 不会尝试写入由 new[] 调用大小为 0,但字符串不为空 终止。然后,在代码的后面,非空终止的字符串是 复制到 std::string 中进行存储,这会导致读取缓冲区 溢出。我也很困惑,只是在这里检查一下 std::string 会让事情更容易理解。

    嗯...原谅我,但如果 this 是您的问题,那么所有这些解决方案似乎都过于复杂。如果问题归结为您获得 0 作为所需的缓冲区大小(这意味着您最终将得到一个不是 NULL 终止的字符串,因为 NULL 终止符没有空间),那么只需确保NULL 终止符始终存在:

    int arraySize; 
    
    /* assume arraySize is set to the length we need */
    ...
    
    /* overallocate by 1 to add an explicit NULL terminator. Just in case. */
    char *ptr = malloc(arraySize + 1);
    
    if(ptr != NULL)
    {
        /* zero out the chunk of memory we got */
        memset(ptr, 0, arraySize + 1);
    
        /* call OpenGL function */
        cStyleAPI(ptr, arraySize);
    
        /* behold, even if arraySize is 0 because of OpenGL, ptr is still NULL-terminated */
        assert(ptr[arraySize] == 0);
    
        /* use it */
        ...
    
        /* lose it */
        free(ptr);
    }
    

    在我看来,这似乎是最简单、最明智的解决方案。

    【讨论】:

    • 应该是最简单的吧。只是好奇:使用mallocmemset 而不是calloc 有什么特别的原因吗?
    • 或者 new[] 和 delete[],就这点而言?
    • 正如我所说 - 只是习惯。随意使用你最喜欢的内存分配器;)
    • +1,我现在实施的修复与此非常相似,尽管我仍然对如何处理可能使用它的周围代码中的错误有一些疑问解决方案更混乱。这个问题在过去的其他情况下也出现过,所以我想看看如果我以后发现自己再次问这个问题,我的选择是什么。
    【解决方案3】:

    是的,但您需要使用 c_str 方法传递它们以保证空终止。

    【讨论】:

      【解决方案4】:

      不,它不是,但通常是因为 C 字符串被假定为零终止,而您的指向char 的指针不是。 (如果你使用string,你可以使用string::c_str(),那是0-终止的。)

      无论如何,C++11 确实要求 vector 的元素在内存中是连续的。

      【讨论】:

        【解决方案5】:
        cStyleAPI(&myArray[0], arraySize);
        

        如果您的 cStyleAPI 收到一个 char* 作为输入,这就是 std::string::c_str() 的用途。

        如果它接收到一个预先分配的 char* 用于输出,则 no。在这种情况下,您应该使用std::vector&lt;char&gt;std::array&lt;char&gt;

        【讨论】:

          猜你喜欢
          • 2021-11-07
          • 2012-06-02
          • 2021-10-27
          • 1970-01-01
          • 1970-01-01
          • 2016-06-26
          • 2015-09-26
          • 1970-01-01
          相关资源
          最近更新 更多