【问题标题】:Missing C11 strerrorlen_s function under MSVC 2017MSVC 2017 下缺少 C11 strerrorlen_s 函数
【发布时间】:2017-11-09 20:08:47
【问题描述】:

我正在尝试从 MSVC 2017 下的 C11 standard 中为 strerrorlen_s 函数包含哪个标头。我需要它来为strerror_s 获取的错误消息分配空间。代码如下:

auto size = strerrorlen_s(errno) + 1;
char* errorReason = (char*)alloca(size);
strerror_s(errorReason, size, errno);
std::ostringstream oss;
oss << "Cannot open: " << fileName << " Reason: " << errorReason;
throw std::runtime_error(oss.str());

在文档中有以下文字:

与所有边界检查函数一样,只有在实现定义了__STDC_LIB_EXT1__ 并且用户在包含string.h 之前将__STDC_WANT_LIB_EXT1__ 定义为整数常量1 时,才能保证strerror_s 和strerrorlen_s 可用。

MSVC 2017 没有定义__STDC_LIB_EXT1__,似乎在包含string.h 之前定义__STDC_WANT_LIB_EXT1__ 没有效果。虽然strerror_s 可用。

  • strerrorlen_sWindowsMSVC 2017 下是否可用?
  • 如果该功能不可用,是否可以通过其他方式获取错误消息长度?
  • strerror_s 线程在 Windows 下是安全的,因为在 Linux 下似乎不是,如果需要线程安全,必须使用 strerror_r,但是它在 Windows 上不可用?

【问题讨论】:

  • 你也缺getline()吗?
  • @Badda 没有getline 可用。
  • @Aconcagua RSIZE_MAX 宏的值为2147483647。为错误消息分配这样的内存是非常不切实际的。 :)
  • @bobeff Truth - MinGW 似乎没有提供它(至少我在任何地方都找不到它......)并且我假设了一些更有意义的价值。来自here,我发现了它的真正含义。作为主要的 C++ 开发人员(rsize_t 实际上不是那里标准的一部分),我不太了解这个新的 C11 特性。很抱歉给了不好的建议...
  • 你为什么不能简单地做oss &lt;&lt; "Cannot open: " &lt;&lt; fileName &lt;&lt; " Reason: " &lt;&lt; strerror(errno);

标签: c++ visual-studio tr24731


【解决方案1】:

Microsoft Visual Studio 在用作 C 编译器时,大多遵循 1990 版的 C 标准。最近有人尝试将其更新为 1999 年版本的语言。他们仍然远远落后 - 编译器与 2011 版本相去甚远。如果您需要符合标准的 C 编译器,则不能使用 VS。

此外,您似乎在 C++ 模式下使用编译器,这并不完全有助于符合 C 标准...C11 和 C++11 并不总是兼容。

话虽如此,您要求的功能是可选边界检查接口的一部分,我相信编译器很少(如果有的话)已经实现了它。边界检查接口中存在的一些功能在 VS 之前的 C11 中作为非标准扩展存在。它们不一定符合标准。

不保证库函数是可重入的。它们可能是线程安全的,也可能不是线程安全的。

【讨论】:

  • windows下的GCC(MinGW)好像也不支持这些功能。
  • @Lundin 你知道是否有可能在strerrorlen_s 函数不可用后以某种方式估计C++ 中错误消息的最大大小?
  • @bobeff 如果您使用 GCC,运行时可能支持%m printf 标志。你可以使用snprintf(buf, size, "%m")
  • @bobeff 可能的最长消息是 94 个字符,因此您可以使用固定长度为 95 的数组(以考虑空终止)
  • @Ryan 你有任何可以支持你的陈述的参考资料吗?
【解决方案2】:

你可以找到实现here:Reini Urban 的 safeclib

// Safe C Library
// 
// Copyright (C) 2012, 2013 Cisco Systems
// Copyright (C) 2017 Reini Urban
// All rights reserved.
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

size_t strerrorlen_s(errno_t errnum)
{
#ifndef ESNULLP
#define ESNULLP         ( 400 )       /* null ptr                    */
#endif

#ifndef ESLEWRNG
#define ESLEWRNG        ( 410 )       /* wrong size                */
#endif

#ifndef ESLAST
#define ESLAST ESLEWRNG
#endif

  static const int len_errmsgs_s[] = {
    sizeof "null ptr",               /* ESNULLP */
    sizeof "length is zero",         /* ESZEROL */
    sizeof "length is below min",    /* ESLEMIN */
    sizeof "length exceeds RSIZE_MAX",/* ESLEMAX */
    sizeof "overlap undefined",      /* ESOVRLP */
    sizeof "empty string",           /* ESEMPTY */
    sizeof "not enough space",       /* ESNOSPC */
    sizeof "unterminated string",    /* ESUNTERM */
    sizeof "no difference",          /* ESNODIFF */
    sizeof "not found",              /* ESNOTFND */
    sizeof "wrong size",             /* ESLEWRNG */
  };

  if (errnum >= ESNULLP && errnum <= ESLAST) 
  {
    return len_errmsgs_s[errnum - ESNULLP] - 1;
  }
  else 
  {
    const char *buf = strerror(errnum);
    return buf ? strlen(buf) : 0;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-19
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多