Ребус с знакобеззнаковыми переменными или когда 208 == -48, а когда и нет

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

Бился 3 дня и решил, что возможно кому-то интересно будет.

два массива

char data[8]
uint8_t rec_data[8]

Переодически, в коде скетча идет попарное сравнение некоторых элементов массива и начинаются чудеса.
На примере в data[1] содержится B11010000 и в rec_data[1] B11010000, понятно, что интерперитируется это как -48 и 208 соответственно.
Тупое сравнение if (data[1] == rec_data[1]) может давать как истину, так и ложь в разных частях скетча. От чего зависит - непонятно. Причем даже указание явного преобразования ((uint8_t)data[1] == rec_data[1])не помогает! Такое впечатление, что иногда преобразование происходит по битовой маске, а иногда просто тупым отбрасыванием знака.
Может кто, что прояснить по данному вопросу? 

vk007
Offline
Зарегистрирован: 16.06.2015

В Serial выведите то, что непосредственно сравниваете и увидите, что и с чем сравнивается на самом деле.

Попробуйте еще добавить скобок: (((uint8_t)data[1]) == rec_data[1]). Я не помню приоритета обработки выражений (надо бы поискать и освежить в памяти), а так кто его знает, может (uint8_t) применяется уже к результату (data[1] == rec_data[1]).

upd. Хотя нет, приведение к типу имеет больший приоритет http://ru.cppreference.com/w/cpp/language/operator_precedence

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

char по умолчанию - знаковый.  

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

DetSimen пишет:

char по умолчанию - знаковый.  


Это подразумевается в посте как само-собой. Так же как int и long. В чем ценность данной информации для данной проблематики?

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

vk007 пишет:

В Serial выведите то, что непосредственно сравниваете и увидите, что и с чем сравнивается на самом деле.

Если в Сериал выводить без преобразования типа - отражается один и тот же нечитаемый символ. А если преобразовывать, то ценность вывода в сериал теряется. Так, что данный фокус не прокатывает.
Надо понимать точно логику работы компилятора при сравнении знакового и безнакового числа. Может и то и другое к int преобразовается вообще...

vk007
Offline
Зарегистрирован: 16.06.2015

Ну тогда попробуйте принудительно приводить к одному типу не один, а оба сравниваемые параметры ((uint8_t)data[1] == (uint8_t)rec_data[1]).

P.S. В Serial выводите не сам символ, а его код.

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

vk007 пишет:

Ну тогда попробуйте принудительно приводить к одному типу не один, а оба сравниваемые параметры ((uint8_t)data[1] == (uint8_t)rec_data[1]).

P.S. В Serial выводите не сам символ, а его код.


Да вопрос не в том как победить костылем - я уже сделал. Вопрос в том, из-за чего это происходит. Лично я натыкаюсь на трудновыловимые проблемы неявного преобразования знака/беззнака при операциях сравнения уже второй раз. И каждый раз это страшная боль и часы потерянного времени. Хочется понимать что и как происходит и обходить это, а не засирать код явными преобразованиями где надо и не надо.

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

Sr.FatCat пишет:

Вопрос в том, из-за чего это происходит. 

Блин, тема муссируется уже пять часов, ну, Вы,блин, когда-нибудь скетч выложите? Нормальный такой пример, с текстом программы (чем короче, тем лучше) и текстом - что в сериал печатается. Так чтобы видна была проблема. Или так и будем сферического коня в вакууме обсуждать: "Эй мужики, у Sr.FatCat там чего-то не получилось, какие будут версии?"?

Пока нет скетча, вся эта тема

Sr.FatCat пишет:

 это страшная боль и часы потерянного времени. 

vk007
Offline
Зарегистрирован: 16.06.2015

Sr.FatCat пишет:

Хочется понимать что и как происходит и обходить это, а не засирать код явными преобразованиями где надо и не надо.

А что тут понимать? Ни у компилятора, ни у самого контроллера нет хрустального шара. И программа выполняется так, как Вы ее написали, а не как задумали. ЕвгенийП прав, без скетча мы пока что ведем всего лишь милую беседу и строим гипотезы фактически ни о чем.

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

Чем вам поможет трехфайловый скетч, если Вы не понимаете сути вопроса? Или как прикажите его уменьшить, чтобы Вы насладились видом четырех if-ов? И как вы собираетесь мне ответить, если не понимаете, что переменну в Serial нельзя запихать "как есть"? Точнее,
что это ничего не дает, потому, что типа char изначально  и выводится одним символом, независимо от того, со знаком он или без. А явное преобразование - сразу убивает суть вопроса на корню.

И,vk007, не надо со мной как с дебилом на пальцах и шарах. У меня компилятор и контроллер делают, то что я задумал - именно потому, что я знаю как они работают. Но в С, есть масса нюансов с неявным приведением типов. И "на раз" я не нашел ответ в стандарте. Более того, нет гарантии что GCC впишется по этому вопросу в стандарт. Так, что вопрос у меня имеено для "милой" беседы и обсуждения гипотез, если нет точных ответов на этот вопрос. Просто ответьте мне в каких строках будет "истина", а в каких "ложь"
 

char a = -48;
unsigned char b = 208;

bool foo(uint8_t x, y) {return x==y;}
bool bar(int8_t x, y) {return x==y;}


if (a==b) ....;
if (b==a)....;

if (bar(a, b))....;
if (bar(b,a))....;
if (foo(a,b))....;
if (foo(b,a))....;


А если я к описанию переменных добавлю const, а если к параметрам функций?

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

Sr.FatCat пишет:

, если Вы не понимаете сути вопроса? 

Просто ответьте мне

Здоров ли ты, брат?

Как же мы ответим, если не понимаем?

Успехов!

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Sr.FatCat пишет:

Просто ответьте мне в каких строках будет "истина", а в каких "ложь"

8 и 9 строки ложь будет

11-14 истина, потому что в 8 и 9 сравниваются разные типы, а в 11-14 строках идет приведение типа и происходит то что вы назвали "сравнение по маски".

Можете проверить вставив в ваши функции вывод в сериал типа Serial.println(x, DEC);

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

Sr.FatCat пишет:

Чем вам поможет трехфайловый скетч,

Ничем. Его даже читать никто не будет.

Если на маленьких несколькострочных скетчах эффект не проявляется, значит его нет, а есть ошибка в Вашем трёхфайловом скетче. А если проявляется - так покажите.

Sr.FatCat пишет:

если Вы не понимаете сути вопроса? 

Как же нам понимать, если нам не показывают проблему?

Sr.FatCat пишет:

как прикажите его уменьшить, 

Никак не прикажу. Проблема у Вас, а не у меня. Я понимаю преобразования типов и вопросов по преобразованию у меня не возникает. Так что хотите - уменьшайте, не хотите - не надо, мне пох. 

Sr.FatCat пишет:

И как вы собираетесь мне ответить, если не понимаете, что переменну в Serial нельзя запихать "как есть"?

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

Sr.FatCat пишет:

вопрос у меня имеено для "милой" беседы 

Тогда Вы ошиблись форумом. Вот вот сюда.

Sr.FatCat пишет:

 если нет точных ответов на этот вопрос.

Будут точные вопросы, будут и точные ответы, а "для милой беседы" ... я уже давал ссылку.

Sr.FatCat пишет:

Просто ответьте мне в каких строках будет "истина", а в каких "ложь"

Вы решили поиграть в учителя и учеников? Ну-ну ... сами "просто отвечайте" - у меня нет проблем с преобразованием типа. У Вас есть - Вот Вы и отвечайте. Я был готов ответить на конкретный вопрос, если бы Вы снизошли его задать.

А по поводу приведённого текста - сначала синтаксические ошибки исправьте, а то у Вас ни в каких строках ничего не будет, кроме ругани компилятора :)

Sr.FatCat пишет:

А если я к описанию переменных добавлю const, а если к параметрам функций?

А если Земля на небесную ось наскочит?

Это и есть милая беседа? :)))

 

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

Вообщем жопа из которой растут ноги здесь:
The conversion rank above increases in order bool, signed char, short, int, long, long long. The rank of any unsigned type is equal to the rank of the corresponding signed type. The rank of char is equal to the rank of signed char and unsigned char. The ranks of char16_t, char32_t, and wchar_t are equal to the ranks of their underlying types.

The following implicit conversions are classified as integral promotions:
 
        signed char or signed short can be converted to int;
        unsigned char or unsigned short can be converted to int if it can hold its entire value range, and unsigned int otherwise;
        char can be converted to int or unsigned int depending on the underlying type: signed char or unsigned char (see above);
Comparing signed and unsigned:
 -1  < 1? false
 -1  > 1? true
Comparing signed and smaller unsigned:
 -1  < 1? true
 -1  > 1? false

Короче, в ногу себе действительно, мешай знаковые и беззнаковые можно выстрелить отлично. Будьте бдительны!

 

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

Ну, слава Богу, вот и мило побеседовали.

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

Sr.FatCat, знаковые и беззнаковые числа расширяются по-разному.

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

Например:

(myByte & 0x00FF) всегда будет трактоваться как число положительное.