![]() |
[C#] Из жизни багов: байты в циклах
МиниКвест.
Недавно выловил такой вот баг в программе: Требовалось перебрать все значения байта от 0 до 255. Как оказалось, это сделать не так-то просто :) Очевидный, на первый взгляд код, не работает: Код:
for (byte b = 0; b <= 255; b++) |
так там после 255 идет 0
т.е. если будет число 255, то оно проверится по условию. цикл выполнится, далее число увеличится на 1. А так как это байт, то оно станет = 0 и тогда опять процдет проверку. достаточно было бы поставить < 256 чтобы исключить такое. Это собственно говоря проблема любого языка. |
А да точно. туплю. Просто не ткомпилятора под рукой чтобы проверить. тогда типа так:
Код:
for (byte b = 0; b <= 255; b++) |
Цитата:
Цитата:
Код:
procedure TForm1.Button1Click(Sender: TObject); |
Цитата:
|
Algol, в C-like во всех так будет. Это не бага ЯП, это бага программиста.
|
Цитата:
Я разве спрашивал/утверждал чей это баг? |
Цитата:
Решение: Использовать CompareTo() рабочий пример: Код:
byte b = 0x0; |
Цитата:
|
Цитата:
{ Console.WriteLine(byte.MinValue + i); } rofl, теперь нет нуля? :))))) |
а с char'ом ещё смешнее - он ещё и signed :)
я так обходил Код:
UCHAR b = 0; |
Цитата:
|
Цитата:
|
Цитата:
|
а в JavaScript все работает:
Код:
for(b=0;b<=255;b++)document.write(b); |
Цитата:
|
Вариант 1
Код:
byte b = 0;Код:
byte b = 0; |
Код:
static bool print(byte b)в плюсах можно ещё красивее сделать |
Цитата:
|
Цитата:
|
Код:
for (unsigned char b = 0; (std::cout<<(int)b++<<"\n")&&(b!=0); ); |
Цитата:
Код:
for (byte b = 0; (std::cout << b++ << std::endl) && b; ); |
Цитата:
Цитата:
|
Algol, миниквест пора заканчивать. Говори правильный ответ. Мне кажется постпроверка с префиксным инкрементом в этом случае оптимальный вариант. По крайней мере по количеству используемой памяти )
|
SitraIT, ыыы, типа вот этого чтоли:
Код:
function MyClass(){З.Ы. вообще имхо это не классы и объекты, а костыли))) |
по-моему ответ где-то тут
Код:
.method private hidebysig static void Main() cil managed |
Цитата:
Правильный - любой который работает :) Лично я бы писал так как предлагал slesh: Код:
for(byte b=0;b<=255;b++)Еще мне понравился вариант desTiny, что на C# выглядело бы типа такого Код:
byte b = 0;Да и кстати, вообще-то я спрашивал почему же исходный код не работает, а все почему то начали приводить примеры работающих кодов :D Раз никто не ответил, отвечу сам: На самом деле, в си-подобных языках нет оператора for в чистом виде. Фактически for это цикл while, для которого указано условие продолжения (b<=255) и некторый оператор, изменяющий b (b++). Причем условние продолжения цикла проверяется на каждой итерации. Когда значение b достигает 255, цикл отрабатывает, и далее выполняется операция b++, результатом которой является снова 0! Далее проверяется условие b<=255 - оно очевидно выполняется, и цикл идет дальше, таким образом зацикливаясь в бесконечность. Для си в принципе это поведение нормальное, однако для C# лично мне это кажется не очень логичным поведением. Логичнее было бы на 255++ генерировать исключение (что то типа OverflowException) - ведь фктически происходит переполение. Но нет, он тихо сбрасывается в ноль и идет себе дальше :( Точно такая же ситуация возникает и для всех остальных целочисленных типов. Например цикл for(int i=0;i<=int.MaxInt;i++) - тоже зацикливается. Получается что стандартный код типа for(int i=1;i<=arr.Count;i++) является небезопасным, так как если arr.Count==int.MaxInt, то цикл будет бесконечным :[ |
спасибо кэп...
|
Мне это напомнило такой код на с:
Код:
int a[10], i;Вот и задачка. А ну-ка скажите, почему это происходит? ;) Кстати, если чуть подправить код, программа и в новых компиляторах будет получаться вечная. |
Цитата:
|
Дружно учим C#:
PHP код:
|
каким образом Algol вывел логическую цепочку от целеноправленного введения for в бесконечны цикл.... до отсутствия реализации for как цельной структуры а не цикла while не понятно (для программиста компилятора это узкоспециализированная задача и реализовывать он ее может в соответствии с быстродействием или оптимизацией памяти, никто же не заставляет его использовать реализацию while)
http://i010.radikal.ru/0912/ff/071f1fb29023.jpg ... по вашей логике все в этом мире сведется к циклу loop (ассемблера) а все остальное от лукавого?????? :D цикл for в примере algol-а не на миг не ушел от описния Керниган Ричи....(не делали же списиально списифического описания for для шарпа) дак что же задавать вопрос о том "..а почему он не разворачивает конфеты?" Вопросы переполнения переменных это азы Си 8))) Школьники многих школ .... где преподают Си вместо Паскаля ВАМ ПОДТВЕРДЯТ ЭТО :D :p для С# не придумывали новый синтаксис ни для 'for' ни для if ни для while или until, используется стандартные функции подходящие под описание языка Си и мне программировать совершенно без разницы на TurboC MSVC Net или шарпе без разницы что касается основных структур языка а если я хочу переполнять .... ПОЧЕМУ РАЗРАБОТЧИК КОМПИЛЯТОРА должен запретить мне в соответствии с синтаксисом переполнять переменную чтоб превратить ее в ноль? такой прием я видел дважды один раз в реализаци победителя конференции AES - блочном шифровании 2fish... каждый можете сделать аналог for и понять разницу между while(... ) {.....} и do {....} while(....); только тот кто использует for 8))) и сам знает как им пользоваться В СООТВЕТСВИИ С ОПИСАНИЕМ 8))! |
Цитата:
|
Цитата:
|
Цитата:
Почему же? Выделяется вполне... |
Цитата:
Могу объяснить более подробно, что и имел ввиду: 1) Цикл for в Си действительно органозован через while. И даже не столько в синтаксическом плане, сколько в логическом. На каждой итерации - проверяется некое условие, и выполняется некое действие. По сути - это while, просто синтаксически оформленный иначе. Но, если мы посмотрим на теорию программирования (безотносително к какому-либо языку), то смысл for - совсем другой. Смысл for - повторить свое тело заданное число раз. Причем некоторые языки дают даже более жесткое определение - повторение своего тела определенное и заданное наперед число раз. Именно такое поведение реализуется в Паскале (Школьники многих школ .... где преподают Паскаль вместо Си ВАМ ПОДТВЕРДЯТ ЭТО :D ). И это правильно, ибо это ближе к изначальному определению for. В Си же (как и во многих других вещах) решили не париться и сделали for через while. А приведенный выше пример как раз и демонстрирует недостаток такого подхода. В Паскале же этот цикл работает без проблем. Он и не может не работать, ведь смысл конструкции for i:=0 to 255 do; в том, что i последовательно принимает значения от 0 до 255, и никаких i++ тут нет, поэтому и переполнения тут никакого быть не может в принципе. Конечно, где-то там внутри , в откомпилированном exe i++ где-то есть , но отсутсвие побочных эффектов, переполения нам гарантирует компилятор, и мы об этом не должны думать. Надеюсь понятно изложил? Да и к тому же фразу о том, что в Си по факту нет for - придумал не я. Слышал давно очень, уже и не вспомню откуда :) 2) Касаемо C#. Да, сишарп по синтаксису близок к Си, но семантика и идеология языка - гораздо ближе к Паскалю, чем к Си. Именно поэтому я и написал что си-подобное поведение шарпа в данном случае не очень ожидаемо. |
Цитата:
|
память под а выделяется. тока она на стеке. а цикл идет <= 10, компиль видимо генерит так, что переменная i лежит за массивом(a[10] указывает на i). таким образом i при значении 10 затирается нулем, с помощью выхода за границы массива. видимо как то так
Цитата:
Код:
for(; b < 255;){} |
Цитата:
|
8)) ... ну еще раз повторюсь .... програмисты используют особенности работы for (в Си понимании) .... кароче ВСЕХ С НОВЫМ ГОДОМ !! :p
|
| Время: 04:53 |