Итерация C до очень большого числа - предупреждение компилятора о unsigned int

У меня есть следующий фрагмент кода:

#include <stdio.h>
#define POWER 10000000000000000000

int main()
{
    int i;
    for (i = 0; i < POWER; i++)
    {
         ....
    }
    return 0;
}

и компилятор gcc выдает следующие предупреждения:

ex1.c:33:19: предупреждение: целочисленная константа настолько велика, что является беззнаковой [включено по умолчанию] ex1.c:33:2: предупреждение: эта десятичная константа беззнаковая только в ISO C90 [включено по умолчанию]

Как я могу выполнить итерацию с i, просматривая все значения, пока не достигнет POWER? Я попытался объявить i как unsigned int, но предупреждения остались.


person Marievi    schedule 19.04.2016    source источник
comment
вы действительно хотите зациклиться 10000000000000000000 раз? for (long i = 0; ; i++) технически будет делать то же самое (бесконечный цикл)   -  person Dmitry Bychenko    schedule 19.04.2016
comment
@DmitryBychenko Я пытаюсь перебрать очень большие числа, так что да, мне нужно повторять так много раз.   -  person Marievi    schedule 19.04.2016
comment
#define POWER 10000000000000000000 --›› #define POWER 10000000000000000000ULL и int i; --›› unsigned long long i;   -  person joop    schedule 19.04.2016
comment
@Marievi: это потребует огромного количества времени, лет как минимум   -  person Dmitry Bychenko    schedule 19.04.2016
comment
@joop Большое спасибо! Моя проблема с компиляцией решена :)   -  person Marievi    schedule 19.04.2016
comment
Что такое it? Я попытался объявить его как unsigned int, но предупреждения остались. Является ли it переменной i или константой POWER?   -  person chux - Reinstate Monica    schedule 19.04.2016
comment
Я не понимаю близких голосов. Я получаю те же предупреждения, когда компилирую код в вопросе.   -  person Keith Thompson    schedule 19.04.2016


Ответы (2)


Для представления вашей константы 10000000000000000000 требуется 64 бита. В шестнадцатеричном формате это 0x8ac7230489e80000. Он может быть представлен в 64-битном типе unsigned, но не в 64-битном типе signed.

Начиная с C99, все целочисленные константы имеют некоторый тип со знаком: первый из int, long int или long long int, в котором значение будет соответствовать.

У C90 (у которого еще не было long long int) были другие правила. В C90 десятичная целочисленная константа без суффикса имеет тип int, long int или unsigned long int.

Режим gcc по умолчанию — -std=gnu90, который поддерживает стандарт C90 и расширения, специфичные для GNU. Если вы работаете в 64-битной системе, long и unsigned long являются 64-битными. В соответствии с правилами C90 ваша константа имеет тип unsigned long (при условии, что unsigned long имеет длину не менее 64 бит). В соответствии с правилами C99 и более поздних версий, если не существует целочисленного типа шире 64 бит, это является нарушением ограничения. (версия gcc 5 изменила значение по умолчанию на -std=gnu11.)

Компилятор, который, по-видимому, работает по правилам C90, предупреждает вас, что значение 10000000000000000000 различается в зависимости от того, в какой редакции стандарта работает компилятор.

Вы можете заставить свою программу «работать» со следующими изменениями:

#define POWER 10000000000000000000ULL // suffix to specify the type
...
for (unsigned long long = 0; i < POWER; i ++)
...

Но хотя это делает программу действительной, это не делает ее практичной. При одной итерации в наносекунду для завершения этого цикла потребуется более 3 столетий. Мой собственный достаточно современный компьютер выполняет одну итерацию пустого цикла for примерно за 1,6 наносекунды. Какую бы проблему вы ни пытались решить, я предлагаю либо найти другой способ ее решения, либо свести ее к меньшей проблеме. Самый быстрый способ выполнить этот цикл — подождать несколько десятилетий, пока оборудование станет быстрее, а затем затем скомпилировать и выполнить его.

(Это предполагает, что тело цикла нетривиально. Если тело цикла ничего не делает, компилятор может вообще оптимизировать цикл.)

person Keith Thompson    schedule 19.04.2016
comment
По правилам C90 ваша константа имеет тип unsigned long. Ты уверен насчет этого? В C++ десятичный литерал никогда не преобразуется в беззнаковый тип. Я не совсем уверен в C, хотя. - person Bathsheba; 19.04.2016
comment
@Bathsheba: Да, я уверен. Я только что проверил свою копию стандарта C90 (ISO/IEC 9899:1990 (E)). - person Keith Thompson; 19.04.2016
comment
#define POWER 10000000000000000000U достаточно. (ЛЛ не нужен). LL имеет небольшой недостаток, скажем, на платформе со 128-битным unsigned long long, и LL без необходимости делает константу большего типа. - person chux - Reinstate Monica; 19.04.2016
comment
Кстати, поправьте меня, если я ошибаюсь, но GCC недавно переключился на gnu11 в качестве диалекта по умолчанию. - person AnT; 19.04.2016
comment
@AnT: Да, начиная с версии 5. Но многие дистрибутивы по-прежнему используют более старые версии по умолчанию. Если вам не все равно, вы должны явно указать версию с помощью -std=.... - person Keith Thompson; 19.04.2016

Значение 10000000000000000000 (= 10 ^ 19, если я правильно посчитал) требует 64 бита для выделения, это 8 байтов. Вы получаете предупреждение, потому что тип int использует 4 байта и поэтому не может хранить это число. С unsigned int вы удваиваете максимальное положительное число, которое вы можете сохранить, но это 4 294 967 295, чего все еще недостаточно. Если вы хотите использовать int, вы можете использовать повторяющиеся циклы.

    for(i=0;i<p;i++){
        for(j=0;j<p;j++){
            for(k=0<p;k++){
            /*loop*/
            }
        }
     }

Где p будет int или unsigned int со значением кубического корня СИЛЫ (в этом случае кубический корень недействителен, поскольку 19%3 != 0, а p не будет int, это скорее идея, чем фактическое решение )

person Nevado    schedule 19.04.2016
comment
Вы получаете предупреждение, потому что тип int использует 4 байта и поэтому не может хранить это число --> Нет. Предупреждение возникает, потому что 10000000000000000000 не помещается в long long. (C99) или в unsigned long (C90). Диапазон int не является проблемой. - person chux - Reinstate Monica; 19.04.2016