C/С++: максимальный размер связанных с errno строк (во время компиляции)

Вопрос

Есть ли способ получить максимальный размер любой строки, коррелированной с errno во время компиляции (при препроцессорном времени будет еще лучше)? Например. верхняя граница на strlen(strerror(errno))?

Мои мысли

Самое лучшее, о чем я могу думать, это запустить программу для поиска грубой силы по диапазону int по каждой локали, чтобы получить строку, связанную с каждой парой {errno, locale}, получить ее размер и создать заголовок в этой системе, а затем подключить его к примеру make файл или autoconf или что-то еще. Я не могу придумать лучшего способа сделать это, но кажется смешным, что это будет так: стандартная библиотека для системы имеет встроенную информацию, если только неявно. Неужели нет хорошего способа получить эту информацию?

Хорошо, я признаю, что стандарты C и/или С++ могут разрешать для строк ошибок, сгенерированных во время выполнения, например, (например, strerror(EINVAL), давая строку, полученную из других метаданных времени выполнения, установленных при последнем наборе errno или что-то в этом роде) - не уверен, что это разрешено, и я действительно приветствовал бы такую ​​реализацию, но Я никогда не слышал об одном существующем, который сделал это, или имел более одной строки для данной пары {errno, locale}.

Мотивация

В контексте, что я специально хотел (но я думаю, что этот вопрос ценен более общим образом, как обсуждалось в комментариях), что привело к тому, что этот вопрос состоял в том, чтобы использовать строку ошибок, связанную с errno в syscall/function writev. В моем конкретном usecase я использовал обе строки из argv и errno -связанных строк. Это установило мою "наихудшую" длину до ARG_MAX + some max errno string length + size of a few other small errors).

Каждый документ * nix, с которым я консультировался, по-видимому, указывает, что writev будет (или "может" ), за то, что мало что может сделать в этом случае) ошибка с errno установлена ​​на EINVAL, если сумма значения iov_len переполняются SSIZE_MAX. Интуитивно я знаю, что каждая строка errno, которую я видел, очень короткая, и на практике это не проблема. Но я не хочу, чтобы мой код таинственным образом не выдавал ошибку на какой-либо системе, если это предположение было ложным. Поэтому я написал код для обработки такого случая - но в то же время я не хочу, чтобы этот дополнительный код был скомпилирован для платформ, которые, как правило, явно не нуждаются в нем.

Комбинированный ввод ответов и комментариев до сих пор заставляет меня наклониться к мысли, что в моем конкретном случае использования "правильное" решение состоит в том, чтобы просто обрезать неприлично длинные сообщения, но именно поэтому я задал вопрос, как я изначально: такая информация также помогла бы выбрать размер для буфера strerror_r/strerror_s (* nix/Windows соответственно), и даже отрицательный ответ (например, "вы не можете этого сделать" ) находится в моем вид полезен для обучения других людей.

Похожие

Этот вопрос содержит ответы на строки, указанные strerror_r на VxWorks, но я не чувствую себя комфортно, обобщая это для всех систем.

Ответы

Ответ 1

Библиотека C, которую вы создаете, может не совпадать (возможно, используется библиотека C, совместимая с ABI) или даже точная версия библиотеки C (В GNU/Linux рассмотрим glibc 2.2.5 против glibc 2.23), которые вы выполняете против, поэтому вычисление максимального размера зависящей от языка строки, возвращаемой из strerror, может выполняться только во время выполнения во время выполнения процесса. Кроме того, языковые переводы могут быть обновлены в целевой системе в любое время, и это снова отменяет любые предварительные вычисления этой верхней границы.

К сожалению, нет гарантии, что значения, возвращаемые strerror, являются постоянными для времени жизни процесса, и поэтому они могут также измениться позднее, тем самым аннулируя любое раннее вычисление границы.

Я предлагаю использовать strerror_r, чтобы сохранить строку ошибки и избежать любых проблем с библиотеками, не поддерживающими многопоточность, которые могут вызывать sterror и, возможно, изменить результат строки когда вы его копируете. Затем вместо перевода строки "на лету" вы должны использовать сохраненный результат и, возможно, обрезать до SSIZE_MAX (никогда не произойдет в действительности).

Ответ 2

Я не знаю, что стандарты C или С++ содержат какие-либо утверждения относительно длины этих сообщений. Платформы, которые вам интересны, могут обеспечить некоторые более сильные гарантии, определенные при реализации.

Например, для систем POSIX я нашел следующее в limits.h.

Следующие константы должны быть определены во всех реализациях в <limits.h>:

  • [...]
  • {NL_TEXTMAX}
    Максимальное количество байтов в строке сообщения.
    Минимальное допустимое значение: {_POSIX2_LINE_MAX}

Я считаю, что сообщения об ошибках, созданные strerror, попадут в эту категорию.

Тем не менее, я не могу получить этот макрос в своей системе. Однако у меня есть _POSIX2_LINE_MAX (от <unistd.h>). Это #define d до 2048. Так как стандарт только говорит, что это нижняя граница, это может быть не слишком полезно.

Ответ 3

Стандарты не дают никаких гарантий о границах размера строки с нулевым завершением, возвращаемой strerror.

На практике это никогда не будет проблемой. Однако, если вы параноик об этом, я бы предположил, что вы просто скопировали строку, возвращаемую из strerr, и закрепите ее длину до SSIZE_MAX, прежде чем передать ее в writev.

Ответ 4

Можно с уверенностью предположить, что SSIZE_MAX будет больше, чем самая длинная строка (массив символов), которую strerror возвращает в нормальной C или С++ системе. Это связано с тем, что полезная системная память (используемая непосредственно вашей программой C) может быть не больше, чем SIZE_MAX (целое число без знака), а SSIZE_MAX будет иметь по крайней мере одно и то же количество бит, поэтому с использованием 2-х комплиментной математики для учета подписанный характер SSIZE_MAX (и ssize_t) SSIZE_MAX будет составлять не менее 1/2 размера системной памяти.