Это предупреждение от вашего g ++ - компилятора, и к каждому предупреждению компилятора следует относиться серьезно.
Цикл for вашего кода Cython преобразуется в следующий / похожий код cpp:
std::vector<long>::size_type __pyx_t_7;
Py_ssize_t __pyx_t_8;
__pyx_t_7 = __pyx_v_xxxx_a.size();
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
....
}
Проблема в том, что std::vector<long>::size_type
- это 64-разрядное целое число без знака в 64-разрядной системе, а Py_ssize_t
- 64-разрядное целое число со знаком.
C ++ использует неявное преобразование для встроенных типов, чтобы иметь возможность оценить __pyx_t_8 < __pyx_t_7
, правила можно найти, например, в этом SO-post .
Существует несколько причин, по которым это предупреждение имеет смысл - правила довольно сложны, и опыт показывает, что программисты часто неправильно их обрабатывают. Например, -1<1U
оценивается как false
(см. live ), но
signed char a =-1;
unsigned char b = 1;
std::cout<<(a<b)<<"\n";
печатает 1
, т.е. (a<b)
оценивается как true
(см. live ). Такие причуды могут легко привести к труднодоступным ошибкам.
Более того, исторически, до того, как стандарт был установлен, разные компиляторы по-разному обрабатывали эти преобразования - при переключении на другой компилятор было бы приятно увидеть все места, где поведение можно было изменить - но это не очень важно Nowdays.
Существуют разные стратегии, чтобы избежать этого предупреждения.
1. Перейти с потоком:
Не проще ли сделать i
a size_t
вместо Py_ssize_t
, т.е. cdef size_t i
?
2. В ролях и проверке:
Вы можете явным образом привести и затем проверить, в порядке ли допущения, например,
...
cdef Py_ssize_t i
cdef Py_ssize_t n = <Py_ssize_t>(a.size())
if n<0 :
raise ValueError("too big");
for i in range(n):
...
Вышеизложенное становится довольно громоздким, поэтому обычно его можно извлечь в служебную функцию.
3. Только что произнес:
Кто-то может спросить: "Насколько вероятно, что вектор содержит более 2^63
записей?" и просто пропустите проверку:
...
for i in range(<Py_ssize_t>(a.size())):
print(i)
и затем ... код не работает через 30 лет:)
4. Отключить предупреждение компилятора:
Также можно передать опцию -Wno-sign-compare
компилятору через extra_compile_args
в файле настроек или -c=-Wno-sign-compare
в IPython, что отключит предупреждение во всем коде. Вероятно, безопаснее использовать решение «Just cast», которое отключает предупреждение только в этом месте, а не везде.
Предупреждение не выдается, если целое число со знаком имеет больший размер, чем целое число без знака: в этом случае целое число без знака преобразуется в большее целое число со знаком и соответствует положительному диапазону более крупного типа.
Например, ssize_t
имеет 64 бита, а unsigned int
имеет 32 бита, поэтому 32-битный бит без знака преобразуется в 64-битный ssize_t
перед сравнением - переполнение не будет, поскольку положительные числа до 63 могут быть представлены `ssize_t'.