首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::带有lvalue的字符串构造函数随clang抛出

std::带有lvalue的字符串构造函数随clang抛出
EN

Stack Overflow用户
提问于 2020-05-10 23:14:10
回答 2查看 145关注 0票数 0

我正在使用Matei的方便的zlib C++包装器,但是在macOs上编译时会出错(clang-1100.0.33 )。

代码语言:javascript
复制
 include/strict_fstream.hpp:39:37: error: cannot initialize a parameter of type 'const char *' with an lvalue of type 'int'

问题在于:

代码语言:javascript
复制
/// Overload of error-reporting function, to enable use with VS.
/// Ref: http://stackoverflow.com/a/901316/717706
static std::string strerror()
{
    std::string buff(80, '\0');

    // options for other environments omitted, where error message is set
    // if not Win32 or _POSIX_C_SOURCE >= 200112L, error message is left empty.

    auto p = strerror_r(errno, &buff[0], buff.size());

    // error next line
    std::string tmp(p,  std::strlen(p));
    std::swap(buff, tmp);
    buff.resize(buff.find('\0'));
    return buff;
}

( IIUC与zlib无关,只是尝试以线程安全的方式报告错误)。

如果我改变到这一点:

代码语言:javascript
复制
static std::string strerror()
{
    std::string buff(80, '\0');

    auto p = strerror_r(errno, &buff[0], buff.size());

    // "fix" below
    size_t length = buff.size();
    std::string tmp(p,  length);
    std::swap(buff, tmp);

    buff.resize(buff.find('\0'));
    return buff;
}

我的程序编译并运行良好。

我有两个问题:

  1. 为什么clang不喜欢构造函数std::string tmp(p, std::strlen(p));
  2. 缓冲区在函数的开头声明为长度80。为什么我们还要费心去查长度呢?
  3. 2的答案可能会回答这个问题,但我的版本有什么问题吗?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-10 23:23:50

如果使用int strerror_r(int errnum, char *buf, size_t buflen);,则没有适当的字符串构造函数,程序的格式也不正确。

如果您使用char *strerror_r(int errnum, char *buf, size_t buflen);,那么程序是格式良好的.

标准的C/POSIX库实现会影响您获得的函数。编译器只涉及影响默认可能使用的系统库。

前者是对XSI中指定的POSIX的扩展(实质上是POSIX的一个可选部分),后者是一个GNU扩展。

如果您使用glibc (我不知道这是否是MacOS上的一个选项),您可以控制使用宏获得的版本,尽管XSI兼容的版本在旧版本中不可用。它的文件说:

提供了符合XSI标准的strerror_r()版本的if:(_POSIX_C_SOURCE >= 200112L \x _XOPEN_SOURCE >= 600) &!_GNU_SOURCE

  1. 缓冲区在函数的开头声明为长度80。为什么我们还要费心去查长度呢?

在构造std::string tmp(p, std::strlen(p));中,对我来说,strlen似乎完全没有必要。std::string tmp(p);是等价的。

如果您不需要线程安全,那么最可移植的解决方案是使用标准std::strerror中的C++:

代码语言:javascript
复制
return std::strerror(errno); // yes, it's this simple

如果您确实需要线程安全,那么您可以使用互斥锁将其包装在关键部分。

注意,当使用标准库时,函数的名称strerror保留给全局命名空间中的语言实现。函数应该在命名空间中,或者被重命名。

票数 2
EN

Stack Overflow用户

发布于 2020-05-10 23:27:20

您通常会看到两个不同版本的strerror_r

  • 兼容POSIX的版本,它总是将错误消息存储在提供的缓冲区中(如果成功的话)并返回int (0表示成功,非零表示错误)。
  • 可以将错误消息存储在提供的缓冲区中的GNU版本,也可能不存储错误消息。它返回指向错误消息的char*,该消息可能指向用户提供的缓冲区,也可能指向其他全局静态存储。

这个strerror函数显然是为了使用strerror_r的GNU版本而编写的。

至于你的第二个问题,你需要strlenbuff长80个字符,但实际的错误消息可能更短,只能部分填充缓冲区。strlen正被用来从结尾剪掉任何额外的无符号字符。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61719944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档