LINUX.ORG.RU

[C][чайник][не понимаю]Преобразование типов

 , ,


0

1

Доброго времени суток. Прошу помощи, ибо совсем запутался.

Суть такова. Есть строка, получаемая с контроллера. Выглядит примерно так:

 

unsigned char in_buffer[120] = "44415441FFFF000001029000009000009000009000009000900000900000900000900000900090000090000090000090000090000000000000000075";

Задача: каждые два символа этой строки представляют один байт. Нужно ее расчленить на эти самые пары символов, потом получить из них соответствующие байты и вычислить контрольную сумму, которая получается как сумма всех байт, кроме последнего, инвертированная и плюс 1. Делаю так:

 

void isCorrectCRC(unsigned char * in_buffer)
{
// Check the CRC for correctness
    int i;
    unsigned char temp_buffer[2];
    int scan_result = 0;
    unsigned char crc = 0;
    unsigned char temp_crc = 0;

    for (i = 0; i < 59; i++)
    {
        temp_buffer[0] = in_buffer[2 * i];
        temp_buffer[1] = in_buffer[2 * i + 1];
        scan_result = sscanf(temp_buffer, "%2X", &temp_crc);

        crc += temp_crc;

        printf("%d\t%d\n", temp_crc, crc);
    }

    crc = ~crc + 1;

    printf("%d\n", crc);
    printf("done\n");

}

Версия функции, естественно, не окончательная. Но вот беда: результат получается неправильный. Прогон под отладчиком показывает, что внутри цикла переменная crc почему-то обнуляется! Что я делаю не так?

PS: последние два символа — это и есть тот самый байт контрольной суммы, который нужно получить.



Последнее исправление: decadent (всего исправлений: 3)

unsigned char temp_buffer[2];
temp_buffer[0] = in_buffer[2 * i]; 
temp_buffer[1] = in_buffer[2 * i + 1]; 
scan_result = sscanf(temp_buffer, "%2X", &temp_crc); 

Не знаю в чем у тебя там проблема. Но если функция принимает строку, заканчивающуюся символом '\0', то надо ей передавать именно такую строку. БЕЗ ИСКЛЮЧЕНИЙ.

А вообще выкинь sscanf и сделай перекодирование вручную.

pathfinder ★★★★
()
Ответ на: комментарий от sotlef

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

decadent
() автор топика
Ответ на: комментарий от sjinks

- unsigned char temp_buffer[2];

+ unsigned char temp_buffer[3];

+ temp_buffer[2] = '\0';

Пробовал и так. Та же фигня.

decadent
() автор топика
unsigned char temp_crc = 0; scan_result = sscanf(temp_buffer, "%2X", &temp_crc);

scanf-ом никогда не пользовался. Напомните, какой размер temp_crc ожидает scanf 8 бит или 32?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Заглянул в man

x соответствует беззнаковому шестнадцатеричному числу; следующий указатель должен являться указателем на unsigned int.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Но если функция принимает строку, заканчивающуюся символом '\0', то надо ей передавать именно такую строку. БЕЗ ИСКЛЮЧЕНИЙ.

Пробовал и ноль дописывать — ничего.

А вообще выкинь sscanf и сделай перекодирование вручную.

Хотелось бы «малой кровью» решить задачу, без написания своих велосипедов.

decadent
() автор топика

> внутри цикла переменная crc почему-то обнуляется! Что я делаю не так?

Ничего удивительного. unsigned char - это числа от 0 до 255, т.е., unsigned char crc = 256 == 0.

kulti ★★
()
Ответ на: комментарий от pathfinder

[quote]

x соответствует беззнаковому шестнадцатеричному числу; следующий указатель должен являться указателем на unsigned int.

[/quote]

Хм, этого я не учел.

decadent
() автор топика
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
        unsigned char crc = 0;
        char in_buffer[120] = "44415441FFFF000001029000009000009000009000009000900000900000900000900000900090000090000090000090000090000000000000000075";
        char tmp[3];
        tmp[2] = 0;
        for (int i=0; i<120-2; i+=2) {
                tmp[0] = in_buffer[i];
                tmp[1] = in_buffer[i+1];
                crc += strtol(tmp, NULL, 16);
        }

        crc = (~crc) + 1;

        printf("%2X\n", crc);
        return 0;
}
sjinks ★★★
()
 

- unsigned char temp_crc = 0; 
+ unsigned int temp_crc = 0;

- crc += temp_crc;
+ crc += (char)temp_crc;

Вот так вроде бы заработало. Спасибо за наводку. А есть ли в таких преобразованиях какие-нибудь подводные камни, о которых я не знаю?

decadent
() автор топика
Ответ на: комментарий от sjinks

crc += strtol(tmp, NULL, 16);

Спасибо, тоже интересный вариант, на эту функцию я не обратил внимания.

decadent
() автор топика
Ответ на: комментарий от decadent

у меня на gcc 4.4.3 работает только если передавать в sscanf строку с '\0' на конце, т.е. с

unsigned char temp_buffer[3];
и зачем
crc += (char)temp_crc; 
???

najar
()
Ответ на: комментарий от najar

у меня на gcc 4.4.3 работает только если передавать в sscanf строку с '\0' на конце

Да, я тоже ноль дописываю.

и зачем crc += (char)temp_crc;

Потому как контрольная сумма — один байт. Чтобы потом вручную обрезание не делать.

decadent
() автор топика
Ответ на: комментарий от decadent

и зачем crc += (char)temp_crc;

Потому как контрольная сумма — один байт. Чтобы потом вручную обрезание не делать.

Хотя сейчас проверил без преобразования типов — тоже работает.

decadent
() автор топика
Ответ на: комментарий от decadent

Спасибо компилятору) Но лишним преобразование не будет. Хотя в С преобразование типов в явном виде писать не всегда обязательно в отличии от С++, но читабельность кода это улучшает на мой взгляд.

Dikar ★★
()
Ответ на: комментарий от Dikar

> atoi() does not detect errors.

Ну вот и накойчёрт такую гадость использовать? Причём всё равно в glibc это обёртка вокруг strtol(str, NULL, 10), так что даже никакого выигрыша в скорости в общем случае не будет. Т.е. это даже не strcat/strcpy, которые ещё имеют смысл, если чётко понимать, что делаешь...

kemm
()

Как все усложнили...

1) Никакие scanf или atoi использовать не надо. 2) Никакие нули в конце «строки» тоже не надо. Это же не строки, а просто буферы. 3) Делать вроде:

int decodeControllerReply(unsigned char *dst, unsigned char *src, int dst_len)
{
.....
    if((src[x] >= 'A') && (src[x] <= 'F'))
    {
        one_hex = src[x] - 'A' + 0xA;
    }
........
    if(even_byte)
    {
        dst[x] = one_hex;
    }
    else
    {
        dst[x] += (one_hex << 4);
    }
.....
}
Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.