Да, такое они ловят. Видимо, предсказание на сколько-то итераций вперёд.
Ну я давно говорю, что семантика переполнения должна быть управляема контекстом — и ни знаковая с "программист должен сам", ни беззнаковая с модулем не должны быть единственными, а умолчанием вообще должна быть неотложная генерация ошибки.
Здравствуйте, netch80, Вы писали:
EP>> for(int i=INT_MAX-2; i>=0; ++i) { EP>> cout << i << " "; EP>> } EP>>Таки закольцевался int, правда jmp'ом N>Да, такое они ловят. Видимо, предсказание на сколько-то итераций вперёд.
Здесь видимо следующая логика: i не отрицательное, и только инкрементируется, следовательно отрицательным без прохода по UB оно никак стать не может, поэтому имеем право заменить i>=0 на true.
Не думаю что зависит от количества итераций. Ибо даже если начинать с i=0 — в генерируемом коде всё равно безусловный jmp.
А поставил я INT_MAX-2 лишь для наглядности, чтобы был виден переворот в печатаемых значениях в отрицательные.
N>Ну я давно говорю, что семантика переполнения должна быть управляема контекстом — и ни знаковая с "программист должен сам", ни беззнаковая с модулем не должны быть единственными,
Там где скорость не важна — очевидно можно решить пользовательскими типами, а-ля safe int, saturated int, etc. Там где важна — нужна поддержка железа.
N>а умолчанием вообще должна быть неотложная генерация ошибки.
Было бы неплохо. Например как trap при делении на ноль.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здесь видимо следующая логика: i не отрицательное, и только инкрементируется, следовательно отрицательным без прохода по UB оно никак стать не может, поэтому имеем право заменить i>=0 на true. EP>Не думаю что зависит от количества итераций. Ибо даже если начинать с i=0 — в генерируемом коде всё равно безусловный jmp.
Да, согласен. Я забыл, что в неудачном варианте было i>0, и не проверил этот от нуля.
У GCC, -O2 и выше без -fno-strict-overflow приводит к удалению проверки.
У Clang, -Og уже достаточно для такого эффекта.
N>>Ну я давно говорю, что семантика переполнения должна быть управляема контекстом — и ни знаковая с "программист должен сам", ни беззнаковая с модулем не должны быть единственными,
EP>Там где скорость не важна — очевидно можно решить пользовательскими типами, а-ля safe int, saturated int, etc. Там где важна — нужна поддержка железа.
Пользовательские типы — да, можно и сейчас, но это от бедности. Для типов, имеющих диапазоны значений не согласно задаче, а согласно железу — лучше задавать контекстом.
Поддержка железа давно доступна в нормальных компиляторах
N>>а умолчанием вообще должна быть неотложная генерация ошибки. EP>Было бы неплохо. Например как trap при делении на ноль.
Ну этот trap в Unix неудобно ловить.
Я предпочитаю явное исключение (C++) или простановку флага.
Здравствуйте, netch80, Вы писали:
N>Поддержка железа давно доступна в нормальных компиляторах
Я имел в виду около-бесплатную железную поддержку на happy path, то есть без необходимости жонглирования флагами в asm, постоянной их проверкой, а посредством вызова установленного обработчика если вдруг произошло переполнение.
Здравствуйте, netch80, Вы писали:
H>>>Во-вторых, иногда нужно не-валидное значение чего-то, что по смыслу неотрицательно. И для этого я лично использую «-1». И если переменная равна ему, то значит значение невалидное. Такая штука с unsigned не проканает, если не вводить всякие magic digits конечно. PJ>>std::optional<uint>
N>И терять 4-8 байт вместо одного бита ;[
Здравствуйте, Evgeny.Panasyuk, Вы писали:
N>>Поддержка железа давно доступна в нормальных компиляторах
EP>Я имел в виду около-бесплатную железную поддержку на happy path, то есть без необходимости жонглирования флагами в asm, постоянной их проверкой, а посредством вызова установленного обработчика если вдруг произошло переполнение.
z/Arch: ставишь PSW бит 20 в единичку и любое переполнение в арифметической команде даёт немедленное исключение. Для адресной и прочей беззнаковой арифметики используется другой набор команд (типа, ALR вместо AR), но тогда у тебя не будет немедленного статуса типа "<0".
MIPS: зовёшь какую-нибудь add вместо addu, и даже битика режима не надо ставить.
Но в нормальных современных процессорах, даже если есть проверки на happy path, за счёт предсказания ветвлений оно в подавляющем большинстве случаев пролетает их сходу, не притормаживая.
Здравствуйте, rg45.
R> Ты зря не послушал совета. Вот признал бы, что ступил, сейчас бы не было необходимости искать пресловутые "дополнительные бубны" там, где их нет, и доказывать, что белое — черное.
Это бесполезно. Ты ничего от него не добьешься
Он воспринимает язык как набор костылей, часть функций которого вообще не пойми зачем нужны.
И чтобы предупредить заранее возможные неправильные интерпретации, сразу скажу: что мой пост касается только утверждений по поводу якобы "кулхацкерских" возможностей цикла for при полном игнорировании того, что эти возможности были изначально в дизайне языка. Это все равно, что ругать какой-нибудь внедорожник за его дополнительные возможности, которых нет у других, "типичных", автомобилей. "Извольте, добрый сер, если застряли, вызывать эвакуатор, как все нормальные люди, а не вытягивать самого себя лебедкой с помощью дерева".
По вопросу знаковых\беззнаковых индексов предпочту воздержаться от комментариев.
Здравствуйте, wander, Вы писали:
W>И чтобы предупредить заранее возможные неправильные интерпретации, сразу скажу: что мой пост касается только утверждений по поводу якобы "кулхацкерских" возможностей цикла for при полном игнорировании того, что эти возможности были изначально в дизайне языка.
Изначальный дизайн языка, говоришь?
Вот код, который честно использует возможности языка, нравится такое читать?
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
Так вот, изначальный дизайн — говнище, и народ нашёл распространённые практики, что из этого дизайна таки пригодно к употреблению, а что надо выжечь огнём нафиг. Но мамкины хацкеры продолжают заниматься мозговым онанизмом...
W>Это все равно, что ругать какой-нибудь внедорожник за его дополнительные возможности, которых нет у других, "типичных", автомобилей. "Извольте, добрый сер, если застряли, вызывать эвакуатор, как все нормальные люди, а не вытягивать самого себя лебедкой с помощью дерева".
Это как ругать собранный на коленке самодельный автомобиль за то, что в его конструкции есть наклейки СПАРКО, сабвуфер в багажнике и колхозный ксенон. Да, извольте на ДОПах светить теми фарами, которые не слепят встречных водителей.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ты всё ещё предпочтёшь воротить нос от стандартной и лаконичной идиомы
Я такую лаконичность сишную в гробу видал.
Это говно, а не лаконичность.
Лаконичность — это
reverseFor (i: n-1 .. 0);
EP>в пользу более сложного выражения, в котором проще допустить ошибку, которое работает только со знаковыми, из-за субъективной "костыльности" стандартной идиомы?
Фариант с фором гораздо более универсален. А вот ваш вайл с беззнаковыми придётся мутить по-особому для перебора от n-3 до m например.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Изначальный дизайн языка, говоришь?
Говорю.
TB>Вот код, который честно использует возможности языка, нравится такое читать? TB>
TB>switch (count % 8) {
TB> case 0: do { *to = *from++;
TB> case 7: *to = *from++;
TB> case 6: *to = *from++;
TB> case 5: *to = *from++;
TB> case 4: *to = *from++;
TB> case 3: *to = *from++;
TB> case 2: *to = *from++;
TB> case 1: *to = *from++;
TB> } while (--n > 0);
TB> }
TB>
Duff`s Device, ага.
Правда я вот больше 20 лет пишу на С и С++ (и не только), и код подобный либо в специальных "инкубаторах" видел, либо в таких вот темах на форуме.
А код с комбинированием операций в секции for встречается постоянно. И ты вообще второй человек в моей жизни, которого это *так* раздражает.
Что характерно первый, как и ты, в C++ пришел из паскалеподобных языков.
Короче говоря, этот пример никак не влияет на то, что концепция цикла for изначально предусматривает его гибкое использование
и не может по определению называться "хакерством".
"Хакерством", например, можно было бы называть метапрограммирование на шаблонах. Duff`s Device — тоже под это подходит, т.к.
использует побочный эффект от того, что метка в С\С++ не вводит области видимости. А c for все нормально.
TB>Так вот, изначальный дизайн — говнище, и народ нашёл распространённые практики, что из этого дизайна таки пригодно к употреблению
Вкусовщина.
TB>мамкины хацкеры продолжают заниматься мозговым онанизмом...
Ты не забыл, что в приличном обществе находишься?
Здравствуйте, wander, Вы писали:
W>Что характерно первый, как и ты, в C++ пришел из паскалеподобных языков.
Ну правильно, пока паскалисты писали простенькие, но рабочие лабы, сишники понтовались очередным бессмысленным способом написать алгоритм через задницу.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Marty, Вы писали:
M>Писать зело больше
int -> uint?
M>Про отрицательные значения и то, что они не используются — ты не можешь быть уверен. Но таки да, может и по лени или недосмотру.
Ну не бывает отрицательного размера памяти
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, netch80, Вы писали:
N>z/Arch: N>MIPS:
О, интересно, не знал что где-то есть.
N>Но в нормальных современных процессорах, даже если есть проверки на happy path, за счёт предсказания ветвлений оно в подавляющем большинстве случаев пролетает их сходу, не притормаживая.
Ну это совсем не бесплатно — арифметика используется повсеместно, в таком варианте её предсказания займут приличный кусок таблицы предсказателя, тормозя всё остальное приложение. На небольших по размеру горячих циклах проблемы нет, но на развесистых итерациях будет проседание.
Здравствуйте, T4r4sB, Вы писали:
EP>>Ты всё ещё предпочтёшь воротить нос от стандартной и лаконичной идиомы TB>Я такую лаконичность сишную в гробу видал. TB>Это говно, а не лаконичность. TB>Лаконичность — это reverseFor (i: n-1 .. 0);
Видимо мы как-то по-разному понимаем слово "лаконичность":
reverseFor(i: n-1 .. 0)
vs
while(n--)
EP>>в пользу более сложного выражения, в котором проще допустить ошибку, которое работает только со знаковыми, из-за субъективной "костыльности" стандартной идиомы? TB>Фариант с фором гораздо более универсален. А вот ваш вайл с беззнаковыми придётся мутить по-особому для перебора от n-3 до m например.
Ну так и замечательно, но вот для обсуждаемого конкретного частного случая while(n--) отлично подходит.
И этот вариант нужно знать, даже если сам не используешь — чтобы моментально парсить сторонний код, где это таки используется. А раз всё равно знаешь — то почему бы не использовать самому?
Здравствуйте, kov_serg, Вы писали:
_>ps: меня больше огорчает всеобщее пристрастие к условию выхода из цикла for(size_t i=0;i!=end;++i){} где исключается одна точка, вместо for(size_t i=0;i<end;++i){} где запрещаются все недопустимые значения.
1. Если там какой-то баг, из-за которого запрещение всех недопустимых значений даёт другой результат нежели исключение точки — то лучше чтобы он проявился как можно раньше, при тестировании, а не молча проглатывался всё время.
Если действительно хочется дополнительно подложить соломки, то намного лучше использовать i!=end, плюс assert(i<end); в начале тела цикла.
2. Не все типы имеющие opreator!=, имеют operator< — особенно важно в обобщённом коде.
Здравствуйте, Sheridan, Вы писали:
S>>>#define counter unsigned int; S>>>for (counter i = 0; i < X; i++) CC>>
S>Ох уж эти милые любители фигурных цитат
Да там одного define достаточно чтобы зафейспалмить.
С "for" просто нагляднее.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока