Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

signed или unsigned, вот в чем вопрос

505
12 февраля 2008 года
vAC
343 / / 28.02.2006
Однажды обсуждал с одним архитектором вопрос об использовании знаковых/без знаковых типов данных.
Моя точка зрения была и пока остается такой:
Цитата:

Без крайней необходимости я не использую беззнаковые типы данных, т.к. это можен повлечь за собой неожиданные ошибки при вычислении выражений со смешанными типами.


У моего же оппонента точка зрения была примерно такая:

Цитата:

Тип данных должен соответствовать смыслу самой сущности, т.е. если у нас целочисленная координата точки на оси, то тип у нее знаковый, если длина отрезка, то беззнаковый.



В какой-то степени я с ним абсолютно согласен, но за эту красоту описания предметной области часто приходиться платить долгими поисками ошибок.

Например, такая задачка:
Есть отрезок. Дана координата одной его точки (x) и длина (length), надо найти координату середины отрезка.

 
Код:
const long x = -6;
const unsigned long length = 2;
const long mid = (x + x + length) / 2;

Такой код конечно же работать не будет. Необходимо делать преобразование к знаковому типу до деления, либо использовать знаковый тип для длины:
 
Код:
const long x = -6;
const long length = 2;
const long mid = (x + x + length) / 2;


В своей пратике подобных ошибок я допускал может и не много, но на их поиск уходило достаточно времени и, согласитесь, такие ошибки не из приятных. Они могут проявиться не сразу, а только при определенных условиях и сразу ответить на вопросы "где" и "почему" очень сложно.

Хотелось бы узнать мнение других по этому вопросу...
1.8K
12 февраля 2008 года
_const_
229 / / 26.11.2003
Прежде всего, надо понять, что середин отрезка две штуки, т.к. откладывать можно как в плюс, так и в минус. Далее непонятно, откуда такие сложности (x+x+length)/2. Не проще было бы так:
 
Код:
long mid1 = x + length / 2;
long mid2 = x - length / 2;

Вроде все ОК.
4
12 февраля 2008 года
mike
3.7K / / 01.10.2002
Мой подход прост - беру с запасом.
590
12 февраля 2008 года
Gigahard
223 / / 03.04.2006
_const_
 
Код:
long mid1 = (x + length) / 2;
long mid2 = (x - length) / 2;

;)

P.S. Сколько будет, два плюс два деленное на два :)
505
12 февраля 2008 года
vAC
343 / / 28.02.2006
Цитата: _const_
Прежде всего, надо понять, что середин отрезка две штуки, т.к. откладывать можно как в плюс, так и в минус. Далее непонятно, откуда такие сложности (x+x+length)/2. Не проще было бы так:
 
Код:
long mid1 = x + length / 2;
long mid2 = x - length / 2;

Вроде все ОК.



Цель примера - показать ошибку, а не найти середину отрезка. Какая разница какая середина и куда откладывать?

P.S. Убедительная просьба постить по-существу, а не "здесь был Вася". Проблему я описал.

505
12 февраля 2008 года
vAC
343 / / 28.02.2006
Цитата: mike
Мой подход прост - беру с запасом.



Так что такое с запасом? Если значение всегда неотрицательно, то использовать unsigned? Или это выбор размера типа данных? - что в данном топике не обсуждается...

1.8K
12 февраля 2008 года
_const_
229 / / 26.11.2003
Цитата: Gigahard
_const_
 
Код:
long mid1 = (x + length) / 2;
long mid2 = (x - length) / 2;

;)


Это к чему?

Цитата: Gigahard

P.S. Сколько будет, два плюс два деленное на два :)


Три. А что?

361
12 февраля 2008 года
Odissey_
661 / / 19.09.2006
Пример мне кажется не корректным - так как выражение со смешанным типом уже наверно стоит задуматься что пойдет что-то не так.

А вот подход вашего друга архитектора мне кажется правильным. Безусловно из правил существуют исключения, но что же теперь из за возможности подобной ошибки отказыватся от логичности определения данных? Так не долго и от const отказатся =)

А вообще как повторял за Хоаром товарищ Кнут - "Преждевременная оптимизация ..." ну а дальше знаешь.
1.8K
12 февраля 2008 года
_const_
229 / / 26.11.2003
Цитата: vAC
Цель примера - показать ошибку, а не найти середину отрезка. Какая разница какая середина и куда откладывать?

P.S. Убедительная просьба постить по-существу, а не "здесь был Вася". Проблему я описал.



Так об этом и речь. Чтобы избежать ошибок, надо внимательно смотреть задачу. А иначе и без unsigned можно натворить всякого.

505
13 февраля 2008 года
vAC
343 / / 28.02.2006
Цитата: Odissey_
Пример мне кажется не корректным - так как выражение со смешанным типом уже наверно стоит задуматься что пойдет что-то не так.


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

Цитата: Odissey_

А вот подход вашего друга архитектора мне кажется правильным.


Мне он тоже кажется правильным, но на практике приводящим к некоторым неудобствам (приведение типов) и ошибкам. Возможно это из-за следующего...

Цитата: Odissey_

Безусловно из правил существуют исключения, но что же теперь из за возможности подобной ошибки отказыватся от логичности определения данных? Так не долго и от const отказатся =)


Вот вы упомянули const и я вспомнил слова Дж. Элджера, примерно такие:

Цитата:

const нужно использовать либо с полной фанатичностью, либо не использовать вообще.


Может здесь и такая же проблема...

1.8K
13 февраля 2008 года
_const_
229 / / 26.11.2003
Кстати, контрпример (short вместо int использован для простоты):
 
Код:
int arr[50000];
for (short i = 0; i < 50000; ++i)
    arr = 1;    // Oops...

В общем, по-моему самый правильный вариант - компилировать с наивысшим уровнем предупреждений. Любой нормальный компилятор при преобразовании signed/unsigned кинет warning.
241
13 февраля 2008 года
Sanila_san
1.6K / / 07.06.2005
Я предпочитаю использовать беззнаковые типы тогда, когда переменные такого типа точно не могут получить отрицательное значение, обычно это счётчики. Кроме прочего, оптимизация на выборе числового типа данных в конкретно моей практике далеко не всегда имеет сколько-нибудь заметное значение. Допустим, у меня имеется циклическое обращение к БД, и в цикле кроме обращения делается ещё много всякой работы. Если у меня по условию задачи заведомо не больше двухсот итераций цикла, я, конечно, могу использовать тип byte вместо привычного integer, я сэкономлю ещё три байта, но если где-то в цикле, скажем, создаётся новый объект, то три байта экономии не изменят решительно ничего ни в быстродействии, ни в затратах ресурсов, а формальная красота выбора правильного типа данных для счётчика в готовом продукте вообще никого не интересует. Поэтому я беззнаковые типы использую только тогда, когда знаковый использовать невозможно или очевидно неоптимально.
361
13 февраля 2008 года
Odissey_
661 / / 19.09.2006
Цитата: vAC
Может здесь и такая же проблема...


Ну мне не кажется это проблемой, это плата за частичную сильную типизацию. Возможность игнорировать или убрать действия правил типизации дает определенную гибкость, но и требует зоркости от программиста =)

324
13 февраля 2008 года
AndreySar
532 / / 01.08.2004
Цитата: Odissey_
Ну мне не кажется это проблемой, это плата за частичную сильную типизацию. Возможность игнорировать или убрать действия правил типизации дает определенную гибкость, но и требует зоркости от программиста =)



Использую безнаковые только в параметрах функции, чтобы предостеречь от неверного указания

 
Код:
GetMid(unsigned int nLength)
3.2K
16 февраля 2008 года
Sania
186 / / 28.10.2006
>Sanila_san
Я за такойже подход...
В Jave например вообще нет беззнаковых типов.
>AndreySar
GetMid((unsigned)-10);

Вцелом любой вменяемый компилятор либо подскажет вам о автоприведении типов, либо потребует явного их указания.
5
16 февраля 2008 года
hardcase
4.5K / / 09.08.2005
В своей работе использую C#.
Всегда использую int (System.Int32), если значимости не хватает - long (System.Int64).
Подобный выбор связан еще с тем, что любые побитовые операции происходят именно над этими типами (остальные типы имплицитно приводятся к ним).
Для вычислений, в которых целочисленные переполнения могут сыграть фатальную роль, стараюсь использовать конструкцию checked { }, а для конструкций, где значимость не важна или даже вредна - сложные операции с битами, счетчики с переполнениями и т.п. - использую unchecked { }.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог