C++:使用std::string在内存中移动jpeg是否安全?

4

我有一个external_jpeg_func()函数,它接收一个char数组作为参数来处理jpeg数据。我无法修改这个函数。为了向其提供char数组,我会像下面这样操作:

//what the funcs take as inputs
std::string my_get_jpeg();
void external_jpeg_func(const char* buf, unsigned int size);


int main ()
{
    std::string myString = my_get_jpeg();
    external_jpeg_func(myString.data(), myString.length() );
}

我的问题是:使用字符串传输字符数组是否安全?JPEG(或任何二进制文件格式)是否有可能遇到像 '\0' 这样的字符并导致数据丢失?


6
安全?可能是的。但是有误导性。如果你只想要一个连续的字节缓冲区,我建议使用vector<char>。 - Oscar Korz
2
当从 char* 加载字符串时,它会在遇到 null 字符时停止,因此不安全。 - Daniel
1
@Dani:如果给定了明确的长度,那就不会出现这种情况。 - Nicol Bolas
@okorz001 直到我看了其他答案后才明白你的意思。@Dani @NicolBolas 我理解给它一个明确的长度很重要。然而,如果字符数组中某处恰好有一个空字符,通常的 string.length()strlen() 方法似乎会失败。有什么建议吗? - Morpork
@Morpork:在处理可能包含空字符的二进制数据时,strlen不应被视为“常规方法”。这就是为什么有一个明确的长度非常重要的原因,因为strlen只告诉你第一个空字符的位置。 - Steve Jessop
3个回答

10
我的建议是在这种情况下使用std::vector<char>,而不是std::string; std::string的危险在于它提供了c_str()函数,大多数开发人员认为的内容以NUL结尾,即使提供了一个size()函数,也可能返回与在NUL处停止得到的不同值。尽管如此,只要您小心地始终使用带有大小参数的构造函数,并小心不将.c_str()传递给任何东西,那么在这里使用字符串没有问题。

虽然使用std::vector<char>而不是std::string没有技术优势,但我认为它更好地向其他开发人员传达了该内容应解释为任意字节序列,而不是以NUL结尾的文本内容。因此,在这里我会选择前者以增加可读性。尽管如此,我已经与使用std::string存储任意字节的大量代码一起工作过。实际上,C++ proto编译器生成了这样的代码(虽然我认为出于我提到的可读性原因,这不是一个好选择)。


2
+1:但我更喜欢std::vector<unsigned char>char仍然传达了与字符(字形、文本)相关的一些语义,而unsigned char更接近于byte概念。 - 6502
1
@6502:如果你所使用的API是以“char”为单位指定的,那么你只需要咬紧牙关... - Matthieu M.
1
在这种情况下,我不同意@6502的观点;大多数需要字节缓冲区的POSIX函数都采用“char *”或“void *”类型;很少见到此类函数采用“unsigned char *”类型。为了避免潜在的混淆或危险转换,我更喜欢保持一致并使用“char”。 - Michael Aaron Safyan
@Matthieu, Micheal Aaron Safyan:我错过了那部分内容,其中说到external_jpeg_function不能被触及。当然,如果它想要一个char *,那么std::vector<char>在我看来是最好的选择。 - 6502
@6502:我认为将char类型与有符号和无符号版本分开的整个意义在于允许IO操作以char为单位工作,并允许平台选择其最适当的版本。因此,char并不意味着“字形”,而是“平台的基本数据单元”。 - Kerrek SB
显示剩余3条评论

6

std::string 不特殊处理空字符,除非你没有给它一个明确的字符串长度。所以你的代码可以正常工作。

尽管在 C++03 中,字符串 技术上 不需要存储在连续的内存中。实际上,几乎所有的 std::string 实现都会以这种方式存储它们,但这并不是必需的。C++11 纠正了这一点。

因此,在这种情况下,我建议您使用 std::vector<char>。与 std::string 相比,std::vector<char> 没有任何优势,并且更明确地表明这是一个字符数组,而不是可能可打印的字符串。


假设我创建了一个 JPEG 图像的向量,逐一将它们馈入 external_jpeg_func()。使用一个字符向量的向量是否明智? - Morpork

2
我认为使用字符数组char[]或std::vector更好。这是保留图像的标准方法。当然,二进制文件可能包含0字符。

实际上,std::vector的规范指出对象内存必须是连续的。因此,如果您有一个std::vector<char> image(10); 并使用"&image[0]",那么它将返回至少10个字节长的内存数组。 - Lucian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接