Являются ли std :: showbase и std :: showpos взаимоисключающими? - PullRequest
5 голосов
/ 08 декабря 2011

Этот вопрос возник из обсуждения, которое я имел о правильном способе вывода числового значения, используя обычный ostream & operator << (ostream &, some_type) для числового типа в C ++.

То, как я знаком с поведениемstd :: showbase и std :: showpos в каждой базе, они в основном взаимоисключающие.То есть: в десятичном виде база не показывается, и к положительным числам добавляется знак «+»;тогда как в шестнадцатеричном или восьмеричном виде отображается основание, но символ «+» не отображается (и не является минусом), поскольку значение типа печатается так, как будто оно приведено к типу без знака.

ДляНапример, эта простая (многословная) программа:

#include <iostream>

int main() {
  std::cout << std::dec << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::oct << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::hex << std::showpos << std::showbase << int64_t(+5) << std::endl;
  std::cout << std::dec << std::showpos << std::showbase << int64_t(-5) << std::endl;
  std::cout << std::oct << std::showpos << std::showbase << int64_t(-5) << std::endl;
  std::cout << std::hex << std::showpos << std::showbase << int64_t(-5) << std::endl;
}

Дает этот вывод при компиляции с GCC:

+5
05
0x5
-5
01777777777777777777773
0xfffffffffffffffb

Это то, чего я всегда ожидал, используя C ++ в течение многих лет, но действительно ли это гарантировано стандартом или это просто обычное поведение?Например, может ли стандартный совместимый компилятор C ++ вместо этого вывести одну из этих последовательностей?

+5
+05
+0x5
-5
01777777777777777777773
0xfffffffffffffffb

или даже:

+5
+05
+0x5
-5
-05
-0x5

Ответы [ 2 ]

3 голосов
/ 08 декабря 2011

Для ios_base само по себе, нет.showpos и showbase вызывают единственный аргумент setf (§27.5.6.1 [fmtflags.manip] / 5 и / 13) в потоке, который не влияет друг на друга.


Если пойти глубже, std::ostream использует функцию locale::facet::put для вывода целого числа (§27.7.3.6.2 [ostream.inserters.arithmetic] / 1) и его реализацию locale::facet::do_put (§22.4.2.2.2 [facet.num.put.virtuals] / 5) указывает:

Все таблицы, использованные при описании этапа 1, упорядочены.То есть применяется первая строка, условие которой истинно.Строка без условия является поведением по умолчанию, когда ни одна из более ранних строк не применяется.

...

Для спецификатора преобразования добавлены следующие дополнительные дополнительные квалификаторы, как указано в Таблице 90.

                  Table 90 — Numeric conversions

+-----------------------+-------------------+------------------+
| Type(s)               | State             | stdio equivalent |
+=======================+===================+==================+
|                       | flags & showpos   | +                |
| an integral type      |                   |                  |
|                       | flags & showbase  | #                |
+-----------------------+-------------------+------------------+
|                       | flags & showpos   | +                |
| a floating-point type |                   |                  |
|                       | flags & showpoint | #                |
+-----------------------+-------------------+------------------+

...

Представления в конце этапа 1 состоят из символов, которые будут напечатаны с помощью вызова printf(s, val), где s - это спецификатор преобразования, определенный выше.

Здесь мы видим, что showpos и showbase находятся в одной и той же ячейке, что, я считаю, стандарт неявно означает, что они находятся в одной и той же «линии», и, таким образом, Обе применяются (это видно из std::cout << std::showpos << std::showpoint << 6.0 для следующей «строки»), и эти два флага здесь все еще не являются взаимоисключающими.


Пока мы видим, что showpos и showbase не являются исключительными в C ++, и фактическое поведение форматирования определяется как printf (хотя реализация не должна использовать printf, например, libc ++ использует sprintf,в то время как libstdc ++ нет) , чтоich мы должны проверить стандарт C.

В C, использование + (showpos) с o и x / X (oct и hex) неопределяется, потому что C99 §7.19.6.1 / 6 и / 8 говорит

+

Результат преобразования со знаком всегда начинается сзнак плюс или минус....

o, u, x, X

Аргумент unsigned int преобразуется в ...

Аргумент не подписан , поэтому + не может применяться.Поведение не записывается, поэтому оно не определено.

Добавление # (showbase) к d (dec) также является неопределенным поведением, как говорится в пункте / 6:

#

Результат преобразуется в «альтернативную форму».Для преобразования o, ... Для преобразования x (или X), ... Для a, A, e, E, f, F, *Преобразования 1103 * и G, ... Для преобразований g и G, ... Для других преобразований поведение не определено.

К сожалению.

Следовательно, не только два флага не являются взаимоисключающими, выходные данные вообще не определены.Упомянутые сценарии 2 и 3 OP могут произойти.В gcc и clang конфликтующие опции (showpos для oct и hex; showbase для dec) просто игнорируются, что создает иллюзию взаимоисключающих двух опций, но стандартне гарантирую этого.

(Отказ от ответственности: я использую n3242 и n1124 в качестве эталона, окончательный стандарт может не совпадать)

0 голосов
/ 08 декабря 2011

Гугл нашел меня эта страница , которая говорит следующее по теме:

Обратите внимание, что отрицательные целые числа не печатаются как таковые в восьмеричном или шестнадцатеричном формате. Скорее, внутренние битовые комбинации интерпретируются как всегда положительные значения.

Если это точно, имеет смысл, что showpos ничего не сделает, зачем показывать + перед числом, которое всегда положительно?

...