std::string 带左值的构造函数抛出 clang
std::string constructor with lvalue throws with clang
我正在使用 Matei David 的 handy C++ wrapper for zlib,但在 macOs 上编译时出现错误 (clang-1100.0.33.
include/strict_fstream.hpp:39:37: error: cannot initialize a parameter of type 'const char *' with an lvalue of type 'int'
问题在这里:
/// Overload of error-reporting function, to enable use with VS.
/// Ref:
static std::string strerror()
{
std::string buff(80, '[=12=]');
// 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('[=12=]'));
return buff;
}
(IIUC与zlib无关,只是试图以线程安全的方式报错)
如果我改成这样:
static std::string strerror()
{
std::string buff(80, '[=13=]');
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('[=13=]'));
return buff;
}
我的程序编译并运行良好。
我有两个问题:
为什么clang不像构造函数std::string tmp(p, std::strlen(p));
?
缓冲区在函数开头声明为长度80。我们为什么还要费心去查找长度?
2的答案可能会回答这个问题,但我的版本有问题吗?
谢谢。
如果使用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 兼容版本在旧版本中不可用。它的文档说:
The XSI-compliant version of strerror_r() is provided if:
(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
- The buffer was declared at the beginning of the function as length 80. Why are we even bothering to look up the length?
在构造std::string tmp(p, std::strlen(p));
中,strlen
对我来说似乎完全没有必要。 std::string tmp(p);
等价。
如果不需要线程安全,那么最便携的解决方案是使用标准 C++ 中的 std::strerror
:
return std::strerror(errno); // yes, it's this simple
如果您确实需要线程安全,那么您可以使用互斥体将其包装在临界区中。
请注意,您的函数名称 strerror
在使用标准库时保留给全局命名空间中的语言实现。该函数应该在命名空间中,或者重命名。
您通常会看到 strerror_r
的两个不同版本:
- 一个 POSIX 兼容的版本,它始终将错误消息存储在提供的缓冲区中(如果成功)和 returns 一个
int
(0
表示成功,非零错误)
- 一个 GNU 版本,可能将错误消息存储在提供的缓冲区中,也可能不存储。它 returns 一个
char*
指向错误消息,它可能指向用户提供的缓冲区或可能指向其他一些全局静态存储。
那个 strerror
函数显然是为了与 strerror_r
的 GNU 版本一起工作而编写的。
关于你的第二个问题,你需要strlen
。 buff
的长度为 80 个字符,但实际的错误消息可能更短并且仅部分填充缓冲区。 strlen
被用来 trim 从末尾开始删除任何额外的 nul 字符。
我正在使用 Matei David 的 handy C++ wrapper for zlib,但在 macOs 上编译时出现错误 (clang-1100.0.33.
include/strict_fstream.hpp:39:37: error: cannot initialize a parameter of type 'const char *' with an lvalue of type 'int'
问题在这里:
/// Overload of error-reporting function, to enable use with VS.
/// Ref:
static std::string strerror()
{
std::string buff(80, '[=12=]');
// 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('[=12=]'));
return buff;
}
(IIUC与zlib无关,只是试图以线程安全的方式报错)
如果我改成这样:
static std::string strerror()
{
std::string buff(80, '[=13=]');
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('[=13=]'));
return buff;
}
我的程序编译并运行良好。
我有两个问题:
为什么clang不像构造函数
std::string tmp(p, std::strlen(p));
?缓冲区在函数开头声明为长度80。我们为什么还要费心去查找长度?
2的答案可能会回答这个问题,但我的版本有问题吗?
谢谢。
如果使用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 兼容版本在旧版本中不可用。它的文档说:
The XSI-compliant version of strerror_r() is provided if: (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
- The buffer was declared at the beginning of the function as length 80. Why are we even bothering to look up the length?
在构造std::string tmp(p, std::strlen(p));
中,strlen
对我来说似乎完全没有必要。 std::string tmp(p);
等价。
如果不需要线程安全,那么最便携的解决方案是使用标准 C++ 中的 std::strerror
:
return std::strerror(errno); // yes, it's this simple
如果您确实需要线程安全,那么您可以使用互斥体将其包装在临界区中。
请注意,您的函数名称 strerror
在使用标准库时保留给全局命名空间中的语言实现。该函数应该在命名空间中,或者重命名。
您通常会看到 strerror_r
的两个不同版本:
- 一个 POSIX 兼容的版本,它始终将错误消息存储在提供的缓冲区中(如果成功)和 returns 一个
int
(0
表示成功,非零错误) - 一个 GNU 版本,可能将错误消息存储在提供的缓冲区中,也可能不存储。它 returns 一个
char*
指向错误消息,它可能指向用户提供的缓冲区或可能指向其他一些全局静态存储。
那个 strerror
函数显然是为了与 strerror_r
的 GNU 版本一起工作而编写的。
关于你的第二个问题,你需要strlen
。 buff
的长度为 80 个字符,但实际的错误消息可能更短并且仅部分填充缓冲区。 strlen
被用来 trim 从末尾开始删除任何额外的 nul 字符。