2015-08-04 2 views
2

Я преобразовываю строковое представление адреса mac в массив из UINT8 s, определенный как unsigned char. Мне любопытно, почему sscanf() будет читать все 0s, когда я прочитал массив из UINT8 s и фактические значения, когда я прочитал массив регулярных 32 бит int s. Его почти так же, как он измельчает 8 бит неправильного конца int.sscanf() hex ints в массив ints против unsigned chars

char *strMAC = "11:22:33:AA:BB:CC"; 

typedef unsigned char UINT8; 
UINT8 uMAC[6]; 

int iMAC[6]; 

sscanf((const char*) strMac, 
     "%x:%x:%x:%x:%x:%x", 
     &uMAC[0], &uMAC[1], &uMAC[2], &uMAC[3], &uMAC[4], &uMAC[5]); 
printf("%x:%x:%x:%x:%x:%x", 
     uMAC[0], uMAC[1], uMAC[2], uMAC[3], uMAC[4], uMAC[5]); 
// output: 0:0:0:0:0:0 

sscanf((const char*) strMac, 
     "%x:%x:%x:%x:%x:%x", 
     &iMAC[0], &iMAC[1], &iMAC[2], &iMAC[3], &iMAC[4], &iMAC[5]); 
printf("%x:%x:%x:%x:%x:%x", 
     iMAC[0], iMAC[1], iMAC[2], iMAC[3], iMAC[4], iMAC[5]); 
// output: 11:22:33:AA:BB:CC 

Update: %hhx будет работать на C99 и выше, но у меня есть старый кодовую, так что я в конечном итоге происходит с strtoul():

char *str = strMac; 
int i = 0; 
for(i = 0; i < 6; i++, str+=3) { 
    uMAC[i] = strtoul(str, NULL, 16); 
} 
+1

Здесь вы вызываете неопределенное поведение, поэтому любое объяснение не будет завершено. –

+0

'char * strMac =" 11: 22: 33: AA: BB: CC ";'? – EOF

+0

@EOF thanks - fixed – ubtac

ответ

5

TL; DR - первый сниппет invkoes UB, потому что несоответствия типа аргумента.


Для разработки, ссылаясь на требование типа аргумента для %x спецификатора формата, от C11 стандарта, глава §7.21.6.2, fscanf() функции, (курсив мой )

x Соответствует необязательно подписанное шестнадцатеричное целое число, формат которого совпадает с ожидаемым для последовательности объектов функции strtoul() со значением 16 для базового аргумента. Соответствующий аргумент должен быть указателем на целое число без знака.

Таким образом, при использовании

sscanf((const char*) strMac, 
    "%x:%x:%x:%x:%x:%x", 
    &uMAC[0], &uMAC[1], &uMAC[2], &uMAC[3], &uMAC[4], &uMAC[5]); 

в вашем коде, вы поставлять неправильный тип аргумента для %x. В соответствии со стандартом, опять же,

[...]. Если подавление присваивания не было указано *, результат преобразования помещается в объект, на который указывает первый аргумент, следующий за аргументом формата, который еще не получил результат преобразования. Если этот объект не имеет соответствующего типа или если результат преобразования не может быть представлен в объекте, поведение не определено.

Таким образом, использование неправильного типа в качестве аргумента вызывает undefined behaviour.


Решение:

Чтобы указать, что вы собираетесь поставить (знаком или без знака) char аргумент типа, вы должны использовать спецификатор формата с префиксом модификатора hh длины, как %hhx с scanf() семьи.

+0

@EOF Как насчет сейчас?:-) –

+0

У меня нет контроля над моей средой сборки (и она запутана), поэтому я не знаю, какую версию C мы используем. % hhx молча завершает работу: я не получаю ошибку компилятора, но это не работает. Но я не понимаю, как sscanf (strMac, "% hhx:% hhx:% hhx:% hhx:% hhx:% hhx", & uMAC [0], & uMAC [1], & uMAC [2], & uMAC [3 ], & uMAC [4], & uMAC [5]) действительный оператор, если hh не является допустимым спецификатором формата. – ubtac

+0

@ubtac '% hhx' был добавлен в 1999 году. Если у вас есть более старая среда, вам придется читать объекты' unsigned int', а затем копировать результаты по одному в свой массив символов. –

Смежные вопросы