Отсутствует функция C11 strerrorlen_s под MSVC 2017

Я пытаюсь найти заголовок для включения strerrorlen_s функция от стандарта C11 под MSVC 2017. Мне это нужно для выделения места для сообщения об ошибке, чтобы получить с 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());

В документации есть следующие слова:

Как и для всех функций с проверкой границ, strerror_s и strerrorlen_s гарантированно будут доступны только в том случае, если __STDC_LIB_EXT1__ определяется реализацией, и если пользователь определяет __STDC_WANT_LIB_EXT1__ к целочисленной константе 1 перед включением string.h,

MSVC 2017 не определяет __STDC_LIB_EXT1__ и кажется, что определяющий __STDC_WANT_LIB_EXT1__ перед включением string.h не имеет эффекта Хотя strerror_s доступен.

  • Является strerrorlen_s доступно под Windows с MSVC 2017?
  • Можно ли каким-то другим способом получить длину сообщения об ошибке, если функция недоступна?
  • Является strerror_s Потокобезопасен в Windows, потому что кажется, что в Linux это не так, и strerror_r должен использоваться, если есть необходимость в безопасности потоков, но он не доступен в Windows?

1 ответ

Решение

Microsoft Visual Studio, когда он используется в качестве компилятора C, в основном соответствует версии стандарта C 1990 года. Недавно были предприняты некоторые попытки обновить его до версии 1999 года. Они все еще сильно отстают в этом - компилятор не приближается к версии 2011 года. Если вам нужен стандартный совместимый компилятор C, вы не можете использовать VS.

Кроме того, вы, похоже, используете компилятор в режиме C++, который не совсем помогает соответствию стандарту C... C11 и C++11 не всегда совместимы.

При этом функция, которую вы запрашиваете, является частью необязательного интерфейса проверки границ, который, я считаю, очень немногие, если таковые вообще имеются, компиляторы еще не реализовали. Некоторые функции, присутствующие в интерфейсе проверки границ, существовали в VS до C11 как нестандартные расширения. Они не обязательно соответствуют стандарту.

Нет никаких гарантий, что библиотечные функции являются реентерабельными. Они могут быть или не быть потокобезопасными.

Вы можете найти реализацию здесь: 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;
  }
}
Другие вопросы по тегам