Милые шалости тернарного оператора

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вчера на амперке всплыла тема про тернарный оператор. ТС ничтоже сумнящеся заявил, что

1sig = <условие> ? <выражение 1> : <выражение 2>;
2 
3// И
4 
5if (<условие>) {
6   sig = <выражение 1>;
7} else {
8   sig = <выражение 2>;
9}

это одно и то же.

Подобного рода заявления встречались и у нас. Я обычно шутил насчёт того, что тернарный оператор открывает широкие возможности для настоящих мужчин (не зря его мисрасты не любят) и на этом ограничивался. А тут вдруг по дискуссии на амперке понял, что многие и вправду не понимают моих шуток и считают, что вышеприведённые конструкции действительно идентичны. Наверное, каждый из вас в своей профессии иногда с удивлением ловил себя на мысли, что оказывается «есть совсем простые вещи, которых неспециалисты не знают»! Вот и я себя поймал на этом. Захотелось исправить ситуацию и рассказать про тернарный оператор. Кто всё это знает – от них не убудет, но уверен, что многие не знают или знают не всё.

Сразу скажу, что приведённые выше куски кода не эквивалентны. Они эквивалентны лишь в частном случае, когда типы <выражения 1> и <выражения 2> в точности совпадают.  Если же типы <выражения 1> и <выражения 2> различны, то ... там как раз открывается простор для творчества. Можно такого наговноко... (простите) натрюкачить, что хрен потом эту ошибку найдёшь!

Изложение построим так. Сначала я кратко поясняю, что происходит, когда эти выражения имеют различные типы и покажу два безобидных примера, демонстрирующих сказанное. Затем, покажу третий пример, в котором из-за этих особенностей программа просто не компилируется. Потом перейдём к более «вонючим» вещам. Четвёртый пример позволяет подобраться вплотную к болоту и ощутить его запах, а уж в пятом примере мы окунёмся в это болото с головой. Ну, и в конце я скажу пару слов «в защиту детёныша».

Итак, если типы <выражения 1> и <выражения 2> различны, компилятор пытается подобрать ближайший общий тип к которому можно преобразовать и то, и другое. Тип он подбирает по общим правилам преобразования типов (несколько страниц в стандарте), а если не может подобрать общий тип, то ругается и прекращает компиляцию.

Давайте посмотрим как это работает.

Пример №1

Здесь <выражение 1> и <выражение 2> имеют типы char и byte соответственно. Serial.print понимает и то, и другое, но печатает их по-разному - char - как символ, а byte - как число. Обратите внимание, что в варианте с if всё именно так и напечатано. А в варианте с ? оба значение напечатаны как числа, т.е. компилятор привёл из оба к типу byte, как к более общему. Т.е. мы уже видим, что программа ведёт себя по-разному при использовании if и при использовании ?.

Пример №2

Приблизительно тоже самое, только с типами int и double. При использовании if они так и печатаются как int и double, а вот при использовании ? - они оба печатаются как double, т.е. компилятор привёл оба значения к типу double.

Иногда бывает так, что сами по себе <выражение 1> и <выражение 2> оба вполне себе подходят для конечного результата, но не могут быть преобразованы к общему типу. В этом случае имеем ошибку компиляции, хотя «эквивалентная» конструкция с if вполне работает. Об этом третий пример:

Ну, что , компилятор не нашёл такого  общего типа, к которому он мог бы преобразовать и const char * и int. Потому он обругал нас и сказал "сами разбирайтесь". Хотя, если бы он ничего не преобразовывал, то print-то вполне был готов скушать хоть const char *, хоть int, что мы и видим в варианте с if - там всё отлично работает.

Для тех, кому уже не терпится спросить: «И что? Это и всё веселье?» пора сказать – нет господа! Веселье ещё и не начиналось! Веселье начинается когда мы начинаем использовать свои собственные типы данных, а не простейшие встроенные типы, как мы делали до сих пор.

Наш четвёртый пример мало отличается от предыдущих, но в нём мы определим свой тип – комплексное число и попробуем в if и в ? напечатать либо его, либо обычное число с плавающей точкой.

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

Вот давайте и посмотрим на более продвинутый пример с конструктором. В пятом примере мы пытаемся создать экземпляр класса String. Как дисциплинированные люди, мы проверяем создался ли экземпляр или для него памяти не хватило. Если создался, то печатаем его, а если не создался, то печатаем сообщение об ошибке. Сообщение – обычная строка – массив символов. Для имитации того, что нам не хватает памяти, мы специально загадим её настолько, чтобы строка уже не создалась и посмотрим, что получится. Итак, пример №5

Как видите с if всё работает! А вот с ? программа зависла! Почему? Ну, понятно, в случае с ? компилятор стал преобразовывать оба выражения тернарного оператора к общему типу. Таковым общим типом является String. Вот он и попытался создать String из нашего сообщения об ошибке! Но ведь на создание String у нас уже нет памяти! Здрасьте, приехали – подвисли :-(

Ну, как? Весело искать такую ошибку, особенно если она не в рафинированном примере,сделанном специально для её демонстрации, а в коде на пару тысяч строк?

И это "мы только зашли туда, чтобы потом всем говорить, что побывали в Лабиринте"! Там чем дальше в лес, тем толще партизаны! А какой простор для творчества предоставляет использование тернарного оператора с автоматическими типами? А с лямбдами? Там такие возможности  говнокодерства открываются - куда там жалкому goto! По творческому потенциалу тернарный оператор можно сравнить разве что с #define.

В общем, тернарный оператор - вещь совсем «не для девочек». Ну, а поскольку программисты - в основном девочки (братья Стругацкие врать не станут), то, например MISRA попросту запретила использование этого оператора наравне с тем же goto.

Теперь обещанная пара слов «в защиту детёныша».

В простых случаях типа чисел одного типа, тернарный оператор выглядит очень компактно и понятно. Также есть достаточно мест, где применим только он и никакими if'ами его не заменишь. Это и условная инициализация ссылок, и условная инициализация членов класса в заголовке конструктора и другое.

Дополнение по результата обсуждения

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

Вот пример:

Результаты с «if» и с «?», как видите, разные.

Но тут мне хотелось бы сделать дополнительные пояснения об операторе присваивания и ещё об одних граблях.

При выполнении оператора присваивания, сначала вычисляется его правая часть. И только потом левая. В нашем случае это означает, что операции преобразования <выражения 1> и <выражения 2> к единому типу будут происходить так, как было описано выше, без оглядки на тип выражения в левой части оператора присваивания! И только потом, будет сделана попытка привести получившийся в правой части «общий» тип к типу левой части.

Отсюда следует, что в принципе возможна ситуация, когда сами по себе <выражение 1> и <выражение 2> вполне могли бы быть приведены к типу левой части, а вот тот «общий» тип, к которому их преобразовали – уже не приводится. В этом случае получим ошибку компиляции.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Евгений Петрович, при всем уважении, крайне разочарован. (((((((((((((

Вначале Вы объявили, что две конструкции не являются эквивалентными, но ни одного подтверждающего это утверждения примера не привели.

Имманентным атрибутом каждого из двух исходных выражений является оператор присваивания (sig = ), но ни в одном из пяти последующих примеров оператор присваивания не используется.

Другими словами, все это очень интересно (как и любой публикуемый Вами материал), но в данном случае, увы, иллюстрация исходного утверждения (о неэквивалентности конструкций, содержащих оператор присваивания) не приведено.

Upper
Offline
Зарегистрирован: 23.06.2020

 

1 sig = <условие> ? <выражение 1> : <выражение 2>;
2  
3 // И
4  
5 if (<условие>) {
6    sig = <выражение 1>;
7 else {
8

   sig = <выражение 2>;

Соответствует:

sig = cTrue() ? Serial.print(c) : Serial.print(b);

if (cTrue()) 
   
sig =Serial.print(c); 
else 
   
sig = Serial.print(b);

А примеры объясняют несколько иное.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
ни одного подтверждающего это утверждения примера не привели.
Вы правда так считаете?

Странно, что Вы не увидели что там совершенно неважно присваивание или нет, а примеры сразу с печатью - исключительно для укорочения кода.

крайне разочарован. (((((((((((((

Вам нужен пример с присваиванием?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Upper пишет:
Соответствует:

А примеры объясняют несколько иное.

Это ложное утверждение.

Upper
Offline
Зарегистрирован: 23.06.2020

ЕвгенийП пишет:

Upper пишет:
Соответствует:

А примеры объясняют несколько иное.

Это ложное утверждение.

Одновременно оба утверждения быть ложными не могут. Или вы делаете логическое И ?

Logik
Offline
Зарегистрирован: 05.08.2014

Увидел

 return digitalRead(2) <= 1;

И дальше смотреть не стал. Магические числа какие-то... Это ж кто так учил проверять результат digitalRead(2)? Архат может?

Смотри в доку!

Функция digitalRead()

digitalRead()
Описание

Функция считывает значение с заданного входа - HIGH или LOW.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Upper пишет:
Соответствует:

А примеры объясняют несколько иное.

Это ложное утверждение.

Женя! Я слышал историю про бисер и домашних животных. Что-то там не очень выходило. ;)

Я завидую твоему терпению, я бы уже начал матюгами щедро посыпать, а потом сердечное ведрами глотать.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Upper пишет:

Одновременно оба утверждения быть ложными не могут. Или вы делаете логическое И ?

Ну, почему же не могут. Вы утверждали

1) что конструкции с if и с ? из первого поста эквивалентны - это ложно ибо они не эквиваленты

2) что мой текст демонстрирует другое - это тоже ложно ибо он именно это и демонстрирует.

Вы, что мне интересно.

Вот Сергей наехал на мою манеру изложения, на то, что я плохо подобрал иллюстрации и доказательства своей главной мысли. Он не в первый раз это делает. Я обычно как-то отгавкиваюсь (как в #3), но прислушиваюсь к нему потому, что обычно в его словах что-то есть :-) В правильности же самой главной мысли он не сомневался потому, что понимает, что она верная.

Вы же попытались объяснить мне, что главная мысль неверна (конструкции эквивалентны), а мои примеры совсем не про неё, а про что-то другое. Вот ответьте мне, Вы правда считаете, что я не понимаю о чём пишу? Или Вы решили меня потроллить, чтобы на слабо заставить сделать пример с присваиванием? Ответьте пожалуйста, а я Вам тогда приз выдам :-)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:
я бы уже начал матюгами щедро посыпать, а потом сердечное ведрами глотать.
Граф, ну ты же знаешь, я же завязал с холиварами.

Будет нормальный разговор, объясню ещё раз, покажу пример именно с присваиванием - их есть у меня, только я не стал приводить, т.к. он посложнее этих. Но вот andriano наехал, что присваивания нет :-( В какой-то мере он, наверное, прав. То, что Upper вообще ничего не понял и утверждает, что конструкции эквивалентны, как раз доказывает правоту andriano. Так я покажу и с голимым присваиванием, и объясню ещё раз (или andriano попрошу объяснить) мне не жалко.

Ну, а не будет нормального разговора - ты знаешь, как я поступаю ( и тебе так советую). Коротко, одноразово и никаких сердечных. А то и вообще молча, как с постом #6.

Upper
Offline
Зарегистрирован: 23.06.2020
Поясню, что я имел в виду.
(Дальше идут мое субективное восприятие, т.е как я прочитал)
 
Автор говорит, что сейчас он покажет что следующие записи могут привести к разному результату
 
sig = <условие> ? <выражение 1> : <выражение 2>;
// И
if (<условие>) {
  sig = <выражение 1>;
} else {
  sig = <выражение 2>;
 
В качестве первого примера рассматривается
if (cTrue()) Serial.print(c); else Serial.print(b);
 
Тогда по условиям задачи 
 
<условие> = (cTrue())
<выражение 1> = Serial.print(c)
<выражение 2> = Serial.print(b)
sig  игнорируется
 
И проверять надо выражение
sig = <условие> ? <выражение 1> : <выражение 2>;
 
sig = (cTrue()) ? Serial.print(c) : Serial.print(b);
 
А в примере проверяют несколько иное.
 
Serial.print( cTrue() ? c : b );
 
Я причитал этот материал как и andriano.
"Другими словами, все это очень интересно (как и любой публикуемый Вами материал), но в данном случае, увы, иллюстрация исходного утверждения (о неэквивалентности конструкций, содержащих оператор присваивания) не приведено."
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Upper,

ну если так, так почему же просто не попросить привести  пример именно с присваиванием? Зачем Вы в посте №2 умничать начали про "несколько иное"?

Вот Вам чистый пример с присваиванием.

Как видите, результаты получаются разные. Почему? Это написано в стартовом посте  - он именно об этом, а вовсе не "несколько иное". 

Изучайте разбирайтесь. А если непонятно - задавайте вопросы, а не ...

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

И тут кроме как "Спасибо дядя Женя !", сказать нечего.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Красиво!

Еще раз убедился, что я не знаю Си++.

Вот в строке 23 используется метод begin() переменной типа String. А в документации по типу String я такого метода не нахожу: https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

И почему, скажем, не m_canonic.c_str()?

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Попкорн на исходе, но с удовольствием слежу!..))

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Я бы сказал они были идентичны до того как Си перерос в С++.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

andriano пишет:
Вот в строке 23 используется метод begin() переменной типа String. А в документации по типу String я такого метода не нахожу

Сереж! Прости плз, но вечер, литр самогона и все эти вещи. Это снова наезд или тебе лень открыть WString.h в коре ардуино ИДЕ?

Б..же! Где Женя берет столько терпения? Может пить нужно меньше? ...или больше? Но что-то делать точно надо!

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

SergeiL пишет:

Я бы сказал они были идентичны до того как Си перерос в С++.

..ля! Нет, это не так. Тернарный оператор ВЫНУЖДАЕТ компилятор приводить к общему типу альтернативы, а if() - нет. Вот и вся разница, из которой много чего можно получить.

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

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

wdrakula пишет:

SergeiL пишет:

Я бы сказал они были идентичны до того как Си перерос в С++.

..ля! Нет, это не так. Тернарный оператор ВЫНУЖДАЕТ компилятор приводить к общему типу альтернативы, а if() - нет. Вот и вся разница, из которой много чего можно получить.

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

А если справа от "?" одинаковые типы данных?

Я бы добавил, На Си в процедуре присвоения всегда должны были использоваться одни типы данных. Отсутствие указания типа, при неявном преобразовании могло внести ошибку, поэтому всегда использовалось явное указание.  

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

brokly пишет:

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

И тут кроме как "Спасибо дядя Женя !", сказать нечего.

Я этим занимался в 80-ых - 90-ых. Разницы в ассемблере не увидел. Но это был компилятор из 80-ых.

Тогда писали свою ОС, я писал библиотеки Си для нашей ОС.  

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Это снова наезд или тебе лень открыть WString.h в коре ардуино ИДЕ?

В коре или в корне?

У меня в папке Ардуино 9 штук WString.h, причем ни одного из них - в корне. А что такое "в коре", я вообще не знаю.

И потом, зачем открывать какой-то файл (кстати, откуда я могу узнать, какой именно файл нужно открывать, если у меня в текущей версии этих файлов 21603 штуки?), если есть официальная документация?

Опять же, даже открыв указанный файл, я не понял, в чем отличие begin() от c_str(), т.к. не понял, для чего нужны одновременно buffer и wbuffer, не говоря о том, почему в данном случае нужен именно wbuffer.

 

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
не m_canonic.c_str()?
Я забыл как он называется. Попробовал m_str - нету такого, полез в исходник - begin - первое, что увидел, что buffer возвращает. Конечно, пофиг какой юзать, лишь бы буфер вернул.

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

MISRA попросту запретила использование этого оператора наравне с тем же goto.

поддерживаю МИСРУ в обоих перечисленных случаях :)

 

Евгений, спасибо!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

пятница, слежу, продолжение будет?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ua6em пишет:

пятница, слежу, продолжение будет?

Я так понимаю, доклад окончен, и идет процесс ответов на вопросы.

Хотите продолжения - задавайте вопрос. Попросите, например, привести пример с присваиванием на Си.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

продолжение будет?

В какой-то мере продолжение.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
Попросите, например, привести пример с присваиванием на Си.
Я, если честно, ожидал просьбы поподробнее раскрыть тему насчёт
ЕвгенийП пишет:
есть достаточно мест, где применим только он (тернарник) и никакими if'ами его не заменишь
Изначально я, кстати, хотел привести такие примеры, но под конец написания уже устал :-(

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

И, да, забыл ответить про Си

Там всё гораздо менее творчески :-( Вот что написано в ISO/IEC 9899:2018, § 6.5.15.

One of the following shall hold for the second and third operands:
— both operands have arithmetic type;
— both operands have the same structure or union type;
— both operands have void type;
— both operands are pointers to qualifed or unqualifed versions of compatible types;
— one operand is a pointer and the other is a null pointer constant; or
— one operand is a pointer to an object type and the other is a pointer to a qualifed or unqualifed version of void.

Там, конечно, можно поиграть с квалификаторами (когда, например, ни с того ни с сего появляется const или volatile), но это очень тонкие вещи и эффектные примеры на них трудно сделать.

vde69
Offline
Зарегистрирован: 10.01.2016

Евгению - спасибо.

Но в моем понимании главной проблемой на которую Евгений не акценитровал внимание новичков - это то, что здесь вопрос не в конструкциях а в контексте применения данных конструкция. Примеров можно приводить много (и из других операторов), но все это сводится к простому правилу:

надо писать просто и единообразно, уж если используем процедурный язык (а с++ это именно процедурный язык) то в нем не стоит использовать подходы из функциональных языков, и все эти "замыкания", и прочие спагетины как в условиях так и в любых других местах применения это вред...

Операторы должны быть простыми.... Особенно для новичков...

зы

если чего, я несколько лет программировал на AutiLisp, и знаю толк в извращениях :)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

andriano пишет:

Хотите продолжения - задавайте вопрос. Попросите, например, привести пример с присваиванием на Си.

Пример ЧИСТО с присваиванием. Женя, позволишь?

Наслаждаемся. Я специально сделал случайные числа, чтобы иногда было одинаково, а иногда нет. Запускать на Нано.

Очень "приятно" подобную ошибку искать в релизе ;)))))))).

01const  int16_t Modulo = 1000;
02 
03template<typename T>
04T mod (T a, int16_t b) {
05  T x = a % b;
06  if (x < 0) return x + b;
07  return x;
08}
09 
10int Wprintf(const char* __fmt, ...) {
11  char s[64];
12  va_list ap;
13  va_start(ap, __fmt);
14  vsnprintf(s, 64, __fmt, ap);
15  va_end(ap);
16  Serial.print(s);
17}
18 
19void setup() {
20  Serial.begin(115200);
21}
22 
23void loop() {
24  int16_t x = random(Modulo);
25  int16_t y = random(Modulo);
26 
27  uint16_t ux = x;
28  uint16_t uy = y;
29 
30  int rIF, rTER;
31 
32  if (x < y) rIF = mod((x - y), Modulo) ;
33  else rIF = mod((uy - ux), Modulo) ;
34 
35  rTER = mod((x < y) ? (x - y) : (uy - ux), Modulo);
36 
37  Wprintf ("if vs ()?():()===> %d %d\n", rIF, rTER);
38 
39  delay(1000);
40}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

Операторы должны быть простыми.... Особенно для новичков...

В этой фразе есть противоречие. Очень часто новичок не понимает что на самом деле просто, а что сложно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Женя! Просто как упражнение для ума. Измени ровно ОДНУ букву в моем примере, чтобы глюк пропал. Ну если интересно, конечно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Граф, ты читер! :-)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

Измени ровно ОДНУ букву

Ты, видимо имел в виду не изменить, а добавить. Букву "u" если точнее. В какое место её добавить колоться не буду - не один я тут :-)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

wdrakula пишет:

Измени ровно ОДНУ букву

Ты, видимо имел в виду не изменить, а добавить. Букву "u" если точнее. В какое место её добавить колоться не буду - не один я тут :-)

Так точно! ;)) Сперва я написал без глюка, и потом пришлось как раз убирать эту "u", чтобы организовать глюк.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Граф, скажи лучше как тебе вот такая фраза из стандарта: Using a bool value in ways described by this document as “undefined”, such as by examining the value of an uninitialized automatic object, might cause it to behave as if it is neither true nor false.

Вот бы пример придумать! Я подумаю, кстати :-)

vde69
Offline
Зарегистрирован: 10.01.2016

ЕвгенийП пишет:

wdrakula пишет:

Измени ровно ОДНУ букву

Ты, видимо имел в виду не изменить, а добавить. Букву "u" если точнее. В какое место её добавить колоться не буду - не один я тут :-)

кстати я недавно попадал, когда наоброт была лишняя эта самая буква u :) 

 

ну что-то типа 

void i;

if ((boolean) i) {}

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

vde69 пишет:

ну что-то типа 

void i;

ты точно понимаешь что пишешь?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Граф, скажи лучше как тебе вот такая фраза из стандарта: Using a bool value in ways described by this document as “undefined”, such as by examining the value of an uninitialized automatic object, might cause it to behave as if it is neither true nor false.

Вот бы пример придумать! Я подумаю, кстати :-)

Думаю... пока компилятор мертво стоит на том, чтобы не дать мне даже попробовать использовать не инициализированный автоматический объект. Думаю, как его наипать?

vde69
Offline
Зарегистрирован: 10.01.2016

DetSimen пишет:

vde69 пишет:

ну что-то типа 

void i;

ты точно понимаешь что пишешь?

так лучше? ну нет у меня на работе ничего для проверки синтаксиса :)

void* i;

if (*((boolean*) i)) {}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Наслаждаемся.

Оно, вроде, красиво, но:

1sketch_apr09a:4: error: 'T' does not name a type
2 
3 T mod (T a, int16_t b) {
4 
5 ^
6 
7exit status 1
8'T' does not name a type

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Сережа! Будь внимательнее при копировании. Ты строчку template<> потерял. Это шаблон. Несколько неожиданно для тебя. За неделю уже вторая странность. Первая была с незнанием понятия "конечная точка".
________
ЗЫ: ты вот скажи: если у тебя появилась ошибка при компиляции, тебе не кажется, что нужно проверить себя в первую очередь??? И не позориться. Фу!

Upper
Offline
Зарегистрирован: 23.06.2020

wdrakula пишет:
если тебе не кажется, что нужно проверить себя в первую очередь??? И не позориться. Фу!

Зафиксирую.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:
Сережа! Будь внимательнее при копировании. Ты строчку template<> потерял. Это шаблон. Несколько неожиданно для тебя. За неделю уже вторая странность. Первая была с незнанием понятия "конечная точка". ________ ЗЫ: ты вот скажи: если у тебя появилась ошибка при компиляции, тебе не кажется, что нужно проверить себя в первую очередь??? И не позориться. Фу!

Нет, Влад, не потерял я ее, просто компилятор приводит лишь тот фрагмент, в котором ошибка, а не весь код примера.

Для контроля только что скопировал код непосредственно из окна своей IDE:

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Сережа! Ну проверь себя. Ну пожалуйста!!! Все работает в штатной ИДЕ 1.8.13. Форум попросить помочь скомпилировать??? Ну блин! Я никогда не публикую код, не запустив. Ты просто оскорбляешь меня, прости за резкость.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Я только что вставил себе в ИДЕ то, что ты опубликовал. Всё, естественно собирается. И проверить это может ЛЮБОЙ находящийся на форуме.

Давай попробуем разобраться. Какая выбрана плата? Какая версия ИДЕ? Не менял ли ты настройки у себя? А ты случайно файл не назвал с расширением ".c", потому что в С нет темплейтов?

========================

Вот видео с записью с моего экрана прямо сейчас. Сергей! Твое поведение - недопустимо!!!!!!!!!!!!!!!!!!!!!!!!!!!

https://youtu.be/1L7wh1Vc3Do

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Коллеги! Очень прошу тех, у кого есть возможность проверить и отписаться! Для меня это ПРИНЦИПИАЛЬНЫЙ вопрос. Меня Андриано обвинил в подлоге, прошу откомпилировать и запустить код даже не из моего, а из его поста!

Я собирал на Нано, Мега, Леонардо. ESP8266 и ESP32. Для ESP32 нужно добавить return в функцмю wprintf, там по умолчанию жесткая проверка возвращаемых типов. Для остальных плат ничего добавлять не надо.

Везде собирается, на 32-битных нет "глюка", понятно почему, если не понятно, объясню я или Женя позже. Сейчас же мне важно разобраться с обвинениями.

Green
Offline
Зарегистрирован: 01.10.2015

Нано, компилируется, запускается.

01if vs ()?():()===> 878 878
02if vs ()?():()===> 666 202
03if vs ()?():()===> 322 322
04if vs ()?():()===> 261 261
05if vs ()?():()===> 86 86
06if vs ()?():()===> 52 52
07if vs ()?():()===> 598 134
08if vs ()?():()===> 308 308
09if vs ()?():()===> 402 402
10if vs ()?():()===> 984 984
11if vs ()?():()===> 627 163
12if vs ()?():()===> 821 357
13if vs ()?():()===> 55 55
14if vs ()?():()===> 271 807
15if vs ()?():()===> 291 291
16if vs ()?():()===> 359 359
17if vs ()?():()===> 706 706
18if vs ()?():()===> 758 294
19if vs ()?():()===> 241 241
20if vs ()?():()===> 479 479
21if vs ()?():()===> 740 276
22if vs ()?():()===> 399 399
23if vs ()?():()===> 837 373
24if vs ()?():()===> 848 384
25if vs ()?():()===> 764 300

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Граф, думаю, andriano тебя тебя троллит. Посмотри внимательно на #29 - вот чует моё сердце, что он твой темплэйт на Си компилирует.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Green! Спасибо!

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Граф, думаю, andriano тебя тебя троллит. Посмотри внимательно на #29 - вот чует моё сердце, что он твой темплэйт на Си компилирует.

"Андриано" в курсе, что обвинения во лжи моё больное место. Я с 6 утра уже не сплю и глотаю бета-блокаторы!!!!! Если ты прав - так еще хуже! Тогда это просто ..дство! ...слов нет! ...сорри!

С++ темплейт там не принципиален, как любой понимает. Можно просто "%" оставить, будет еще нагляднее. Темплейт - украшательство, исправляющее дурь авторов стандарта, по которой "%" может давать отрицательные значения. (в половине ЯП, а в другой (например в Питоне) математики победили).