关于c ++:在c ++ 11中将std :: string转换为char *

Convert std::string to char * in c++11

本问题已经有最佳答案,请猛点这里访问。

我正在为混合语言编写一个库,因此我们必须坚持使用C接口。我需要调用这个API函数:

1
2
void getproperty(const char * key, /* in  */
                 char * value      /* out */) {

我需要用STD::字符串的内容设置值。

1
2
std::string stdString = funcReturningString();
// set value to contents of stdString

我已经看到了许多可能的策略的答案,但是对于这个特定的用例没有一个,也没有被认为是"最好的"或"标准的"。我们使用C++ 11,因为它的价值。有些答案含糊不清地建议将字符串的内容复制到缓冲区并使用它。但是怎么做呢?我想对这次谈话有更多的看法,这样我才能最终选择一个策略并坚持下去。

谢谢您!

更新:这是我使用的解决方案

我使用uint32来保持与其他api函数的一致性。BufferSize是一个引用,因为Fortran通过引用调用所有内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
void getproperty(const char * key,            /* in  */
                 const uint32_t & bufferSize, /* in  */
                 char * value,                /* out */
                 uint32_t & error             /* out */)
{
  std::string stdString = funcReturningString();

  if (bufferSize < str.size() + 1) {
    // Set the error code, set an error message, and return
  }

  strcpy(value, stdString.c_str());
}

我选择strcpy()来保持所有东西的标准,并选择了bufferSize参数,这样我就不必担心注释中提到的双间接寻址的一些问题。


似乎getpropertyAPI调用有缺陷。调用方无法说明value的长度。这意味着getproperty的实现不能安全地写入value,因为它不知道它有多长时间。getproperty方法要么需要更改为取char** value或取value缓冲区的长度作为参数。假设后者完成了

1
void getproperty(const char* key, char* value, size_t valueLength);

现在,为了复制从funcReturningString返回的值的内容,我们只需要使用strncpy

1
2
std::string stdString = funcReturningString();
strlcpy(value, stdString.c_str(), valueLength);

请注意,这仍然有缺陷。如果valueLength == 0或其长度小于字符串的长度,那么这将不起作用。最好是更改getproperty,同时返回某种类型的错误代码,这样就可以将此类故障传达给调用方。


一个简单的方法是:

1
strcpy(value, stdString.c_str());

但您需要小心缓冲区溢出。理想情况下,这个函数的调用者还应该给出它提供的缓冲区的大小,以确保您不会写得超过它的末尾。一种方法是传递一个额外的参数缓冲区大小并使用

1
2
strncpy(value, stdString.c_str(), buffer_size);
if (buffer_size > 0) value[buffer_size-1] = 0;

否则,在复制之前先缩短stdstring。


如果您需要获得值的可修改副本,您应该自己分配内存,value的类型也应该是指向指针的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void getproperty(const char * key, /* in  */
                 char ** value     /* out */) {
  if (value == NULL) {
      // ERROR
      return;
  }

  const std::string& stdString = funcReturningString();

  // if this function is called from C
  // you need to use 'malloc' instead of 'new' operator
  *value = malloc(stdString.size() + 1); // +NUL
  if (*value == NULL) {
      // ERROR mem alloc
      return;
  }

  memcpy(*value, stdString.c_str(), stdString.size() + 1); // +NUL
}

那么你应该这样称呼它(在C上):

1
2
3
4
5
6
char* value = NULL;
getproperty("key", &value);
// use
...
// free it
free(value);


If this is going to target Windows then you generally need to free in the same DLL that you allocate. This is because the linkage with the c-runtime may be with some combination of static/dynamic, single/multi-threaded. In each case it affects how the heap is managed.

如果有很多C运行库,那就太糟糕了。原则上,一个定义规则说程序中应该只有一个malloc和一个free…拥有它们是件好事——)由于性能原因,可优先选用memcpy。另外,当您确实需要复制内存时,为什么要使用迭代器和算法copy而不是memcpy?它提供了什么样的"类型安全"?