2017-02-01 17 views
0


Сценарий заключается в том, что я хочу читать 4 байта данных из заданного указателя, который имеет тип char.
Например: Рассмотрим следующий пример -Как читать 4 байта данных из заданного указателя char в C

int a=0; 
char* c; // This will have some address 

Что я хочу сделать, это прочитать 4 байта, начиная с с (то есть адрес), и назначить их в variable a который является целым числом.

Мое решение:

a = *(int*)c; // Assembly is LDR r1, [r6,#0x00] 

Моя проблема:
Над раствором хорошо работает на некоторых архитектурах, но не на некоторых из них. Чтобы быть конкретным, в моем случае он не работает на Arm CortexM0.

Если кто имеет какой-либо портативный, высокоэффективным (с минимальной сборки) замена моего решения, пожалуйста, поделитесь, было бы большим подспорьем для меня, и я благодарю вас за это заранее;)

Пожалуйста, спросите, если больше информации.

+1

Опишите, как это * не может *. Указывает ли 'c' на другое целое число? – StoryTeller

ответ

5

Проблема может быть из-за выравнивание. Некоторые архитектуры ЦП не могут читать или записывать небайтовые значения на несогласованные адреса.

Решения сделать невыровненные байты-доступ вместо, который можно легко сделать с memcpy:

memcpy(&a, c, sizeof a); 
+2

В этом решении может быть проблема с контентом. –

+0

@someProgrammerDude: Хотя это может решить проблему, но если и сравнить эффективность, мой код генерирует одну команду загрузки ваш будет генерировать Hell много дополнительного кода b/c вызова memcpy Кроме того, у меня нет memcpy, доступного здесь :( – Mrmj

+2

@Mrmj Большинство компиляторов имеют специальную обработку 'memcpy', чтобы сделать их * очень эффективными и могли даже заменить их встроенными только несколькими инструкциями. Вы говорите, что можете закодировать его только с одной инструкцией? Но если проблема связана с выравнивание, то вы на самом деле * не можете * сделать это только с одной инструкцией. Вы также должны учитывать ремонтопригодность и четкость кода, особенно если это не проблема. с оптимизацией и посмотреть на сгенерированный ассемблерный код? –

0

В зависимости от endianness

#include <stdio.h> 

int main(void) 
{ 
    unsigned char bytes[] = { 0xAA, 0x55, 0xAA, 0x55 }; 
    unsigned int a=0; 
    unsigned char* c = bytes; 

    a += (*c++ & 0xFFFFFFFFu) << 0; 
    a += (*c++ & 0xFFFFFFFFu) << 8; 
    a += (*c++ & 0xFFFFFFFFu) << 16; 
    a += (*c & 0xFFFFFFFFu) << 24; 

    printf("HEX: %X\n", a); 

    a = 0; 
    c = bytes; 

    a |= (*c++ & 0xFFFFFFFFu) << 24; 
    a |= (*c++ & 0xFFFFFFFFu) << 16; 
    a |= (*c++ & 0xFFFFFFFFu) << 8; 
    a |= (*c & 0xFFFFFFFFu) << 0; 

    printf("HEX: %X\n", a); 
} 
+0

Это генерирует много (по крайней мере, с моей точки зрения) инструкций по сравнению с моим, который генерирует только одну инструкцию сборки. – Mrmj

+0

Как я писал: если вы знаете о проблемах с контентом, вы можете использовать ваш метод. В противном случае вы должны позаботиться об этом. – LPs

+0

Почему у него есть указатель на целое число в памяти, которое не имеет той же цели, что и процессор? Это кажется довольно не связанным с вопросом. – Lundin

0

Если порядок байт является проблемой для вас:

Вместо:

a = *(int*)c; // Assembly is LDR r1, [r6,#0x00] 

вам это нужно:

На больших системах обратного порядка байт:

a = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; 

На маленьких системах обратного порядка байт:

a = c[3] << 24 | c[2] << 16 | c[1] << 8 | c[0]; 

// probably faster (only on little endian systems) : 
memcpy(&a, c, sizeof a); 
+0

Почему у него есть указатель на целое число в памяти, которое не имеет такой же энзидиентности, как у CPU? Это кажется довольно не связанным с вопросом. – Lundin

2

Есть на многих различные проблемах здесь.

  • Выравнивание. Указатель char должен указывать на выровненный адрес, если вы хотите прочитать целое число по этому адресу.
  • Подпись char. Определяется реализация: char обрабатывается как подписанный или неподписанный. Поэтому это плохой тип для любой формы манипуляции бит/байт. Вместо этого используйте uint8_t.
  • Указатель наложения.Отбрасывание необработанного адреса, на которое указывает char*, на int*, является неопределенным поведением, так как оно нарушает так называемый strict aliasing rule. Это может привести к тому, что ваш код будет неправильно оптимизирован компилятором (особенно gcc). В любом случае, от int* до char* было бы неплохо.

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

Пример портативного, безопасного решения:

#include <stdint.h> 
#include <assert.h> 
#include <string.h> 

#include <stdio.h> 
#include <inttypes.h> 


int main (void) { 

    int x = 123; 
    uint8_t* c = (uint8_t*)&x; // point to something that is an int 
    assert((uintptr_t)c % _Alignof(uint32_t) == 0); // ensure no misalignment 

    uint32_t i; 
    memcpy(&i, c, sizeof(i)); // safely copy data without violating strict aliasing 

    printf("%"PRIu32, i); // print 123 

    return 0; 
} 

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

  • Нет связанных вопросов^_^