2015-12-26 4 views
2

Допустим, у меня есть это:Доступ последовательных записей из массива в C

uint8_t a[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; 

Если я:

printf("%lu", ((uint64_t*) a)[0]); 

Я получаю:

0x0102030405060708 

Как я могу это сделать с нестандартным размером? ех. ((uint94_t) a)[0]. Конечно, нет uint94_t, и это то, о чем я прошу. Как читать нестандартное число бит (или даже байтов, это делает работу для меня тоже)?

Примечание: Я не забочусь о конкретной строке PRINTF (в так что он может анализировать нестандартное количество бит/байт), но в типе данных

ответ

0

Немного прибегая к помощи у меня ответ ... Ответ - битполы!

typedef union { 
    __uint128_t i : 96; 
} __attribute__((packed)) uint96_t; 
printf("%ul", ((uint96_t*) a)[0]); 
+1

примечание: это приводит к неопределенному поведению, также маловероятно, что он выдает выход на 96 бит, попробуйте сделать 'a' 12 байтами, как в моем последнем примере –

2

"%ul" означает "%u" (беззнаковое целое) следует буква "l". Возможно, вы намеревались "%lu" (без знака long), однако оба из них неверны для uint64_t.

Собственный спецификатор находится в inttypes.h, и это "%" PRIu64.

Также это не печатает 0x, как вы предложили, оно печатает десятичное представление. Используйте "%" PRIx64 для шестнадцатеричного представления (которое также не печатает ведущие 0x).


Продолжая, ваш код вызывает undefined behaviour. Согласно правилу строгого псевдонима, не разрешается использовать выражение типа uint64_t для доступа к любой переменной, которая не была записана как uint64_t или int64_t.

Вы можете избежать строгого правила наложения спектров, используя переменную нужного типа, либо в союзе или иным образом, например:

uint64_t x; 
memcpy(&x, a, sizeof x); 
printf("%" PRIu64 "\n", x); 

Ваш компилятор оптимизирует это, так что не беспокойтесь о том, что является неэффективным или что-то.

Обратите внимание, что результат этого равен . Реализация определена, поскольку компилятор мог выбрать различные способы упорядочения бит uint64_t. Два общих заказа: big-endian и малоэтажный.


Другая часть вашего вопроса касается других целочисленных типов. К сожалению, вы застряли в том, что предоставил ваш компилятор. Скорее всего, он не предлагал uint94_t. Вам нужно будет перевернуть свой собственный код, чтобы достичь того, чего вы хотите. Например, вы можете имитировать 96-битовую большой Endian:

uint8_t a[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}; 

uint64_t x = 0, y = 0; 
mempcy((unsigned char *)&x + 4, a, 4); 
memcpy(&y, a+4, 8); 
printf("%" PRIx64 "%" PRIx64 "\n", x, y); 

Конечно, вы могли бы просто напечатать его посимвольно.

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