Почему форматирование длинной переменной в C ++ рассматривает его как int? - PullRequest
0 голосов
/ 21 апреля 2020

Работая с более крупной программой, я нашел фрагмент, который ведет себя странно:

long L = 2500000000L;
fprintf( stderr, "L is %ld\n", L );
fflush( stderr );

Поскольку объявление L равно long, а формат %ld, я ожидал увидеть этот отпечаток как "2500000000", но на самом деле он печатает

L is -1794967296

, что больше, чем я ожидал бы от формата %d.

Однако, если я изменю формат на %uld он печатает 2500000000 правильно, хотя компилятор выдает предупреждение, что L следует объявить unsigned.

Это ошибка в форматировании C ++? Я использую Eclipse + mingw на Windows, указав диалект как c ++ 11.

Ответы [ 3 ]

1 голос
/ 21 апреля 2020

Наибольшее число, которое тип данных long требуется для представления в C ++, равно 2'147'483'647. Другими словами, он должен иметь ширину не менее 32 бит. 2'500'000'000 выходит за пределы этого диапазона.

Windows

В частности, windows, long - это 32-разрядное число, и не сможет представлять 2'500'000'000.

Это ошибка в форматировании C ++?

Не похоже, что это будет.

Однако, если я изменю формат на% uld, он печатает

Если вы сделаете это, поведение программы будет неопределенным, поскольку этот спецификатор формата не соответствует Тип аргумента. Вы также должны изменить тип целого числа.

unsigned long гарантированно может представлять 2'500'000'000 во всех системах.


Если вы хотите быть способным представлять 64-битные числа, тогда наиболее переносимые варианты: long long, std::int_least64_t и std::int_fast64_t, каждый из которых гарантированно будет по меньшей мере 64-битным.

1 голос
/ 21 апреля 2020

2'500'000'000 требуется 32 бита для представления. На некоторых машинах (особенно на Windows машинах) long имеет ширину 32 бита, и 1 бит резервируется для знакового бита, поэтому у вас остается 31 бит, что недостаточно. Чтобы это исправить, вы можете использовать unsigned long, long long или std::int64_t в зависимости от ваших потребностей.

0 голосов
/ 21 апреля 2020

Нет ошибки. Это только означает, что подписанный тип long int в вашей системе имеет такую ​​же ширину, что и тип int. В результате объект типа long int не может представить такое положительное число.

Таким образом, вместо типа long int вы можете использовать тип long long int, например,

long long L = 2500000000;
fprintf( stderr, "L is %lld\n", L );

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

Если целочисленный литерал не имеет суффикса, то из этих типов определяется его тип относительно того, какой тип может представлять значение

int int
long int
long long int

Чтобы проверить, какой целочисленный тип со знаком может вместить такую ​​константу, запустите следующую демонстрационную программу

#include <iostream>
#include <limits>

int main() 
{
    std::cout << 2500000000 << '\n';
    std::cout << std::numeric_limits<int>::max() << '\n';
    std::cout << std::numeric_limits<long>::max() << '\n';
    std::cout << std::numeric_limits<long long>::max() << '\n';

    return 0;
}

Другой подход к определению типа константы заключается в использовании стандартного класса std::is_same, объявленного в заголовке. <type_trais>.

Вот демонстрационная программа

#include <iostream>
#include <iomanip>
#include <type_traits>

int main() 
{
    std::cout << 2500000000 << '\n';

    std::cout << std::boolalpha << std::is_same<int, decltype( 2500000000 )>::value << '\n';
    std::cout << std::boolalpha << std::is_same<long, decltype( 2500000000 )>::value << '\n';
    std::cout << std::boolalpha << std::is_same<long long, decltype( 2500000000 )>::value << '\n';

    return 0;
}

Так что, если использовать вызов printf, требующий указать спецификатор преобразования для выведенного объекта, вы можете написать

auto L = 2500000000;

if ( std::is_same<long, decltype( L )>::value )
{
    fprintf( stderr, "L is %ld\n", L );
}
else if ( std::is_same<long long, decltype( L )>::value )
{
    fprintf( stderr, "L is %lld\n", L );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...