Нужен ли unsigned
От: Аноним  
Дата: 12.11.06 13:13
Оценка: :)
Я решил попробовать писать "правильный" код. Для ширины например — unsigned, т.е. она не бывает отрицательной. И тд.
Но как меня всякие мелочи задолбали, извините. Чуть чуть перепутал, и всё, 4 миллиарда, вся логика валится.
Если int-ы хоть можно проверить на -1, то unsigned-ы как проверишь? Непонятно.
Собственно вопрос, оправдан ли такой геморрой? Или сделать :%s/unsigned/int/g и жить счастливой жизнью?
С одной стороны вроде бы unsigned идеологически лучше. Но с другой, не получается у меня нормально с ними писать. Каждый раз, когда фунцию с аргументом типа unsigned вызываешь, надо проверять, не передастся ли туда отрицательное число, а если бы она была int, то проверку можно было бы сделать внутри функции (ну не писать же
void f(unsigned x)
{
    if ((int)x < 0) // something bad
}
)
Что вы думаете по этому поводу?

18.04.07 14:44: Перенесено модератором из 'C/C++' — Кодт
Re: Нужен ли unsigned
От: Michael7 Россия  
Дата: 12.11.06 13:37
Оценка: +3
Здравствуйте, Аноним, Вы писали:

А>Я решил попробовать писать "правильный" код. Для ширины например — unsigned, т.е. она не бывает


А я наоборот, полагаю, что unsigned, по возможности, надо объявлять только в редких случаях и только для неарифметических по смыслу переменных. То есть таких, над которыми никогда не проводятся арифметические операции. И даже для них, если нет нужды не надо unsigned, так я почти никогда не объявляю unsigned даже индексные переменные. Иначе чревато трудно обнаружимыми ошибками в промежуточных вычислениях.
Re: Всё очень просто....
От: Erop Россия  
Дата: 12.11.06 13:58
Оценка: +2 -3
Здравствуйте, Аноним, Вы писали:

А>Что вы думаете по этому поводу?


signed -- для чисел
unsigned -- для флажков.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Нужен ли unsigned
От: Centaur Россия  
Дата: 12.11.06 14:21
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Я решил попробовать писать "правильный" код. Для ширины например — unsigned, т.е. она не бывает отрицательной. И тд.

А>Но как меня всякие мелочи задолбали, извините. Чуть чуть перепутал, и всё, 4 миллиарда, вся логика валится.

Нужно обращать внимание на warning’и компилятора. И иметь компилятор, который их сыплет по всякому поводу.
Re[2]: Нужен ли unsigned
От: Аноним  
Дата: 12.11.06 14:39
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>>Я решил попробовать писать "правильный" код. Для ширины например — unsigned, т.е. она не бывает отрицательной. И тд.

А>>Но как меня всякие мелочи задолбали, извините. Чуть чуть перепутал, и всё, 4 миллиарда, вся логика валится.

C>Нужно обращать внимание на warning’и компилятора. И иметь компилятор, который их сыплет по всякому поводу.


gcc, -Wall -Wextra
варнингов нет. Да и откуда ему знать, что получится при m_width — m_pageWidth: 10 или 0 или -10
Re[3]: Нужен ли unsigned
От: FDSC Россия consp11.github.io блог
Дата: 12.11.06 14:42
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>gcc, -Wall -Wextra

А>варнингов нет. Да и откуда ему знать, что получится при m_width — m_pageWidth: 10 или 0 или -10

А кто мешает проверить ПЕРЕД операцией?
Re: Нужен ли unsigned
От: Андрей Тарасевич Беларусь  
Дата: 12.11.06 16:40
Оценка: 1 (1) +2 :)
Здравствуйте, Аноним, Вы писали:

А>Но как меня всякие мелочи задолбали, извините. Чуть чуть перепутал, и всё, 4 миллиарда, вся логика валится.

А>Если int-ы хоть можно проверить на -1, то unsigned-ы как проверишь? Непонятно.

Не совсем понятно, причем здесь именно -1.

Также непонятно, откуда взялись эти 4 миллиарда. Такое могло призойти, например, если где-то в программе перемешиваются знаковые и беззнаковые типы или если где-то из меньшего вычитается большее. В первом случае (если мешать signed и unsigned действительно необходимо) надо было проверять на отрицательные значеня непосредственно перед переходом от signed к unsigned. Во втором случае надо было проверять на вычитание большего из меньшего.

А>Собственно вопрос, оправдан ли такой геморрой? Или сделать :%s/unsigned/int/g и жить счастливой жизнью?


Нет там никакого геммороя. В том виде, в котором все это описано в твоем сообщении, это звучит как "беззнаковые типы не дают мне сделать ошибку и я не могу проверить ее наличие"

А>С одной стороны вроде бы unsigned идеологически лучше.


Лучше.

А>Но с другой, не получается у меня нормально с ними писать. Каждый раз, когда фунцию с аргументом типа unsigned вызываешь, надо проверять, не передастся ли туда отрицательное число, а если бы она была int, то проверку можно было бы сделать внутри функции


Удобство unsigned как раз и состоит в частности в том, что их не надо проверять на отрицательные значения. Их надо проверять только на выход за верхний предел, если таковой существует (такая проверка, как правило, отловит и случайную передачу "отрицательного числа"). А если верзхнего предела не существует в принципе — то и проверять ничего не надо.

Откуда возникает проблема "не передастся ли туда отрицательное число" — мне не понятно, ибо не понятно откуда может даже возникнуть возможность передать отрицательное число — то, что передается, тоже должно быть unsigned. Если же в этом месте происходит необходимый переход от signed к unsigned значениям (что бывает нечасто), то проверка, разумеется, делается в момент перехода, т.е. снаружи функции.
Best regards,
Андрей Тарасевич
Re[3]: Нужен ли unsigned
От: Michael7 Россия  
Дата: 12.11.06 16:49
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>gcc, -Wall -Wextra

А>варнингов нет.

Вы добавьте -ansi -pedantic Может появятся

А> Да и откуда ему знать, что получится при m_width — m_pageWidth: 10 или 0 или -10


К сожалению, gcc не выдаёт предупреждений, но в принципе компилятор c/c++ мог бы выдавать предупреждения, если результат вычитания присваивается беззнаковой переменной.
Re[2]: Нужен ли unsigned
От: Michael7 Россия  
Дата: 12.11.06 17:17
Оценка: 1 (1) +4
Здравствуйте, Андрей Тарасевич, Вы писали:

А>>С одной стороны вроде бы unsigned идеологически лучше.


АТ>Лучше.


Чем? На мой взгляд существует очень ограниченный перечень случаев, когда unsigned оправдан, это флаги, коды значений, работа с памятью, может ещё пара случаев и всё. В принципе, ещё можно даже для арифметических операций, если не хватает диапазона значений знакового типа, но это уже грязный стиль и нежелательно.

АТ>Удобство unsigned как раз и состоит в частности в том, что их не надо проверять на отрицательные значения. Их надо проверять только на выход за верхний предел, если таковой существует (такая проверка, как правило, отловит и случайную передачу "отрицательного числа").


Сугубо моё мнение, но у меня сложилось впечатление, что потенциальные проблемы перевешивают преимущества и применение unsigned делает код слегка менее прозрачным, а в некоторых случаях может создать проблемы при модификациях кода. Например, казалось бы логично сделать индекс/счётчик беззнаковым, но в дальнейшем может оказаться, что проще всего присваивать ему отрицательные значения для обработки особых ситуаций.

Дело в том, что использование беззнаковых типов в C/C++, вопреки ожиданиям, практически ничего не даёт в плане контроля за кодом на этапе компиляции, а только добавляет лишнюю сложность и ограничения.
Re[2]: Нужен ли unsigned
От: A.Lokotkov Россия http://www.linkedin.com/pub/alexander-lokotkov/a/701/625
Дата: 12.11.06 19:40
Оценка: 1 (1) :))
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Не совсем понятно, причем здесь именно -1.

АТ>Также непонятно, откуда взялись эти 4 миллиарда.
unsigned someCounter = 99;
while(--someCounter >= 0)
{
  //ooops! infinite loop here
}
bloß it hudla
Re[3]: Нужен ли unsigned
От: Андрей Тарасевич Беларусь  
Дата: 12.11.06 19:53
Оценка:
Здравствуйте, A.Lokotkov, Вы писали:

АТ>>Не совсем понятно, причем здесь именно -1.

АТ>>Также непонятно, откуда взялись эти 4 миллиарда.
AL>
AL>unsigned someCounter = 99;
AL>while(--someCounter >= 0)
AL>{
AL>  //ooops! infinite loop here
AL>} 
AL>


И? Неправильно реализованный цикл работает, разумеется, неправильно. И что из этого?
Best regards,
Андрей Тарасевич
Re[4]: Нужен ли unsigned
От: Michael7 Россия  
Дата: 12.11.06 20:05
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

AL>>
AL>>unsigned someCounter = 99;
AL>>while(--someCounter >= 0)
AL>>{
AL>>  //ooops! infinite loop here
AL>>} 
AL>>


АТ>И? Неправильно реализованный цикл работает, разумеется, неправильно. И что из этого?


Очень хороший пример.

Применение unsigned излишне нагружает программисту мозг, заставляя его лишнего следить за кодом, в то время как казалось бы он мог рассчитывать отдохнуть на более строгом контроле типов.
Re[3]: Нужен ли unsigned
От: Андрей Тарасевич Беларусь  
Дата: 12.11.06 20:17
Оценка: 21 (6) +8 -1 :)
Здравствуйте, Michael7, Вы писали:

А>>>С одной стороны вроде бы unsigned идеологически лучше.


АТ>>Лучше.


M>Чем? На мой взгляд существует очень ограниченный перечень случаев, когда unsigned оправдан, это флаги, коды значений, работа с памятью, может ещё пара случаев и всё. В принципе, ещё можно даже для арифметических операций, если не хватает диапазона значений знакового типа, но это уже грязный стиль и нежелательно.


Чем — это очень странный вопрос. Беззнаковые по своей природе сущности естественно представлять беззнаковыми типами. Тут, собственно, и вопросов никаких нет. Вопросы возникают именно тогда, когда кто-то начинает пытаться использовать знаковые типы для это цели. Вот тут действительно можно спросить, чем это вдруг оправданно такое странное использование знаковых типов. И в большинестве случаев оказывается, что знаковые типы просто-напросто чаще "прощают" беспечное отношение к коду. Во-первых, я считаю, что правильнее внимательнее относиться к коду, а не пытаться компенсировать лень использованием знаковых типов. Во-вторых, "безопасность" знаковых типов — не более чем иллюзия.

АТ>>Удобство unsigned как раз и состоит в частности в том, что их не надо проверять на отрицательные значения. Их надо проверять только на выход за верхний предел, если таковой существует (такая проверка, как правило, отловит и случайную передачу "отрицательного числа").


M>Сугубо моё мнение, но у меня сложилось впечатление, что потенциальные проблемы


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

Вон в соседнем письме приведен пример, в котором использование беззнакового типа приводит к бесконечному циклу. Это пример, который показывает только то, что если писать беззнаковый код в манере знакового, то, разумеется, ничего хорошего их этого не получится. Делать из этого вывод о каких-то недостатках беззнаковых типов — это примерно то же самое, что пытаться писать Паскаль-код на языке С++, и, потерпев неудачу, заявлять, что это свидетельствует о недостатках языка С++.

M>перевешивают преимущества и применение unsigned делает код слегка менее прозрачным, а в некоторых случаях может создать проблемы при модификациях кода.


Я не вижу абсолютно никаких проблем с прозрачностью кода.

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


А вот это — идеологически неправильно.

M>Дело в том, что использование беззнаковых типов в C/C++, вопреки ожиданиям, практически ничего не даёт в плане контроля за кодом на этапе компиляции, а только добавляет лишнюю сложность и ограничения.


Все эти "сложности и ограничения" — не более чем следствие применить порочные штампы мира знаковых типов к беззнаковым. Просто не надо пытаться это делать.

Также стоит упомянуть, что в С++ во многих контекстах выбор в пользу знаковых типов сдела на уровне языка и стандартной билиотеки. Сделан давно и навсегда. Это и 'size_t', и 'sid::vector<>:size_type' и т.п.

Еще стоит упомянуть, что те проблемы "с индексированием" (или с организацией счетчика цикла), который тут часто навязывают беззнаковым типам, на самом деле существуют в языках С/С++ с самого их рождения: например, в области адресной арифметики. Попробуйте организовать просмотр массива методом "скользящего указателя" в обратном направлении — и вам придется решать те же самые вопросы, которые возникают при обратной индексации массива беззнаковым индексом. Эти же вопросы приходится решать и при работе со стандартным итераторами. Так что говорить, что беззнаковые типы создают какие-то присущие именно им проблемы -совершенно неверно. Это не проблемы знаковых типов. Это соврешенно нормальная реальность программирования на С/С++ к которой рано или поздно все равно придется привыкать. А вот упоминающаяся тут манера безусловного использования знаковых типов — это не более чем попытка убежать от этой реальности.
Best regards,
Андрей Тарасевич
Re[5]: Нужен ли unsigned
От: Андрей Тарасевич Беларусь  
Дата: 12.11.06 20:30
Оценка: +3 -1
Здравствуйте, Michael7, Вы писали:

M>Здравствуйте, Андрей Тарасевич, Вы писали:


AL>>>
AL>>>unsigned someCounter = 99;
AL>>>while(--someCounter >= 0)
AL>>>{
AL>>>  //ooops! infinite loop here
AL>>>} 
AL>>>


АТ>>И? Неправильно реализованный цикл работает, разумеется, неправильно. И что из этого?


M>Очень хороший пример.


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


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

int a[N];
int* p = a + N;

while (--p >= a)
  *p = 0;


Типичный 'int'-овый программист зачатсую даже и не видит проблемы в этом коде. Более того, такой код зачастую "работает". В то время как на самом деле этот код приводит к неопределенному поведению и его поведение предсказать трудно. Он запросто может привести и к бесконечному циклу. Решить проблему в данном случае беспечным переходом к какому то "знаковому" типу не удастся. Наду учиться жить в "беззнаковом" мире.

Правильная реализация такого цикла

int a[N];
int* p = a + N;

while (p > a)
  *--p = 0;


является одним из варинатов "шаблонного" решения, применимого и к примеру с unsigned циклом

unsigned someCounter = 99;
while(someCounter > 0) {
  --someCounter
  ...
}


хотя для случая арифметического типа можно поступить и так

unsigned someCounter = 99;
while(someCounter-- > 0) {
  ...
}


Я могу лишь посторить, что специфика "близости края интервала", присущая беззнаковым типам и за которую их часто "не любят", в языках С и С++ присуща далеко не только беззнаковым типам. Если внимательно поискать, найти ее можно практически везде. И спрятаться от нее вам не удастся, как бы вы этого не хотели.
Best regards,
Андрей Тарасевич
Re: Нужен ли unsigned
От: johny5 Новая Зеландия
Дата: 13.11.06 09:18
Оценка: :)
Вместо
void f(int i)
{
  if(i < 0 || i >= cont.size())
     return;
}


можно писать
void f(unsigned i)
{
  if(i >= cont.size())
     return;
}


т.е. сократить одно условие
Re[6]: Нужен ли unsigned
От: johny5 Новая Зеландия
Дата: 13.11.06 09:26
Оценка: :)))
АТ>
АТ>int a[N];
АТ>int* p = a + N;

АТ>while (--p >= a)
АТ>  *p = 0;
АТ>


АТ>Типичный 'int'-овый программист зачатсую даже и не видит проблемы в этом коде. Более того, такой код зачастую "работает". В то время как на самом


Что то я действительно не вижу проблем в таком коде...
Re[4]: Нужен ли unsigned
От: Кодт Россия  
Дата: 13.11.06 09:35
Оценка: +7
Здравствуйте, Андрей Тарасевич, Вы писали:

<>
АТ>Я не знаком ни с какими "потенциальными проблемами" беззнаковых типов. В моем коде, например, практически все целочисленные типы — беззнаковые, за исключением случаев, когда действительно приходится работать со знаковой величиной.
<>

Не столько проблема, сколько неудобство (иногда).
В знаковой арифметике одно и то же неравенство можно выразить несколькими способами: x<y, x-y<0, 0<y-x, а в беззнаковой — единственным x<y. А если слева и справа — по нескольку слагаемых/вычитаемых, то рукодельная нормализация приводит к плохо читаемому коду.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[7]: Нужен ли unsigned
От: night beast СССР  
Дата: 13.11.06 09:35
Оценка: 1 (1)
Здравствуйте, johny5, Вы писали:

АТ>>int a[N];
АТ>>int* p = a + N;

АТ>>while (--p >= a)
АТ>>  *p = 0;


АТ>>Типичный 'int'-овый программист зачатсую даже и не видит проблемы в этом коде. Более того, такой код зачастую "работает". В то время как на самом


J>Что то я действительно не вижу проблем в таком коде...


если не ошибаюсь, сравнение с указателем который указывает не на "элемент массива или элемент после конечного" -- UB.

зачем так мне не известно.
Re[5]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 13.11.06 10:07
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Андрей Тарасевич, Вы писали:


К><>

АТ>>Я не знаком ни с какими "потенциальными проблемами" беззнаковых типов. В моем коде, например, практически все целочисленные типы — беззнаковые, за исключением случаев, когда действительно приходится работать со знаковой величиной.
К><>

К>Не столько проблема, сколько неудобство (иногда).

К>В знаковой арифметике одно и то же неравенство можно выразить несколькими способами: x<y, x-y<0, 0<y-x, а в

В знаковой арифметике эти выражения точно так же не эквивалетны. Кроме того, x<0 не эквивалетно -x>0.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Нужен ли unsigned
От: Шахтер Интернет  
Дата: 13.11.06 10:13
Оценка: :)
Здравствуйте, Michael7, Вы писали:

M>Здравствуйте, Аноним, Вы писали:


А>>Я решил попробовать писать "правильный" код. Для ширины например — unsigned, т.е. она не бывает


M>А я наоборот, полагаю, что unsigned, по возможности, надо объявлять только в редких случаях и только для неарифметических по смыслу переменных. То есть таких, над которыми никогда не проводятся арифметические операции. И даже для них, если нет нужды не надо unsigned, так я почти никогда не объявляю unsigned даже индексные переменные.


Очень плохо.

M>Иначе чревато трудно обнаружимыми ошибками в промежуточных вычислениях.


void func(char *p,size_t s)
 {
  for(int i=0; i<s ;i++) p[i]=0;
 }


Надо обьяснять, где здесь ошибка?
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.