LINUX.ORG.RU

Как неявный каст signed в unsigned сделать ошибкой?

 , ,


3

1
>>> cat test.cpp
int foo(unsigned x) {
	
}

int main() {
	foo(-1);
	return 0;
}

>>> g++ -Wall -Wextra test.cpp

Хочу чтобы компилятор меня посылал когда я пытаюсь передать отрицательное число в unsigned тип неявно вместо того чтобы -1 внезапно становилась 4294967295. Такое поведение ведет к очень плохим багам.

И разрешал мне если я явно попрошу. Те foo(unsigned(-1))

★★★★
Ответ на: Спасибо! от bga_

-Wall это, как ни странно, не все ворнинги:

This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros. This also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.
PhysShell ★★
()
Ответ на: Спасибо! от bga_

Только почему его нету ни в Wall ни в Wextra?

Потому что это предусмотренная стандартом корректная операция.

LamerOk ★★★★★
()
Ответ на: Спасибо! от bga_

у шланга есть опция -Weverything

anonymous
()
Ответ на: комментарий от d_a

Просто(tm) не использовать unsigned

...там где не нужно, и использовать там где нужно. Ваш К.О.

inb4 «нигде не нужно»: арифметика по модулю 2^n это полезная вещь

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Удваиваю 2^n. Битовые маски и Z-кривая Мортона это наше все;-)

AntonI ★★★★★
()

Используй шаблоны. Не вендорлочь на конкретный компилятор, то что можно сделать средствами языка…

#include <type_traits>

template<typename T>
void foo(T /*x*/) {
	static_assert(std::is_same_v<T, unsigned int>);
}

int main() {
	foo(-1);
	return 0;
}

https://gcc.godbolt.org/z/9Enobo1Mj

fsb4000 ★★★★★
()
int foo(unsigned x) {
    return x-3;
}

int foo(int x) = delete;

int main()
{
	foo(-1); // error
	foo(1);  // error
	foo(1u); // OK
	return 0;
}
Beewek ★★
()
Ответ на: Спасибо! от bga_

Вероятно слишком много кода использует -1 для получения 0xFFFFFFFF. Это допустимая операция, в ней нет ничего неопределенного.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: Спасибо! от bga_

По-моему, твой кейс весьма безобиден, гораздо большую проблему представляет смешанная арифметика (где в одном выражении есть знаковые и беззнаковые), результат может зависеть от «расстановки скобочек» в то время как сами операторы в выражении ассоциативны:

int i = 2;
unsigned u = 1;
long l = 1;
assert(u-i+l != u+l-i);

Хз, почему-то так вышло, но integer promotion всегда кастует в int и нет никаких особых правил для смешанных операций. Всегда использую -Wsign-conversion, а в нужных местах делаю вручную каст таким костыльком:

template <integral T>
auto scvt(T t) 
{
	using type_t = conditional_t<is_signed_v<T>, 
		  uintmax_t, intmax_t>;
	return static_cast<type_t>(t);
}

assert(scvt(u)-i+l == scvt(u)+l-i);
scvt(i) + u;
kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 2)

-Werror попробуй

bhfq ★★★★★
()
Ответ на: Спасибо! от bga_

Wall вообще странная вещь, там куча бесполезных мусорных варнингов и нет многих полезных

firkax ★★★★★
()
Ответ на: комментарий от fsb4000

Используй шаблоны. Не вендорлочь на конкретный компилятор, то что можно сделать средствами языка…

Это не вендорлок, варнинг нужен только разработчику, а у него что стоит то стоит. А вот просто так делать код непереносимым в Си (не ++) - не надо так делать.

firkax ★★★★★
()
Ответ на: комментарий от Legioner
(unsigned)-1
(unsigned long)-1
(size_t)-1

Вот это - допустимые операции. А просто так писать -1 там, где ожидается что-то беззнаковое это фу.

firkax ★★★★★
()

Я использую у себя -Wconversion

neon1ks ★★
()
Ответ на: комментарий от bga_
-Wreturn-type -Wpointer-sign -Wsign-compare -Wshadow -Wpointer-arith -Wimplicit -Wformat -Werror -Wno-parentheses -Wuninitialized

Того, о чём тема, среди них нет (хотя может стоит добавить).

firkax ★★★★★
()

Вообще с -Wsign-conversion впереди ожидает некоторое количество боли в виде 100500 мусорных ворингов (привет беззнаковый интерфейс плюсовой стд), если проект не новый, потому его в -Wall и нет. В худшем случае будешь вставлять c-cast’ы или static_cast’ы на каждый ворнинг, scvt - много лучше, но тоже костыль. Кстати, не самые последние люди (не без основания) отговаривают от намерения исключить передачу отрицательных чисел посредством использования unsigned.

kvpfs ★★
()
Ответ на: комментарий от cyberhoffman

Не вендорлочь

Хорошо, что c++23 еще не требует.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.