Проблема приведения указателя к члену массива структуры - PullRequest
0 голосов
/ 16 февраля 2011

Я наткнулся на этот источник в устаревшей кодовой базе, и я действительно не знаю, почему именно он ведет себя так, как он.

В следующем коде член структуры pData содержит данные или указатель на реальные данные в разделяемой памяти. Сообщение отправляется с использованием IPC (msgsnd() и msgrcv()). При использовании указателя (который в настоящее время закомментирован) он не работает с GCC 4.4.1 на цели ARM, член uLen изменяется. При использовании memcpy() и все работает как положено. Я действительно не могу понять, что не так с приведением указателя. Что здесь не так?

typedef struct {
    long mtype;
    unsigned short uRespQueue;
    unsigned short uID;
    unsigned short uLen;
    unsigned char pData[8000];
} message_t;

// changing the pointer in the struct
{
    unsigned char *pData = <some_pointer>;
#if 0
    *((unsigned int *)pMessage->pData) = (unsigned int)pData;
#else
    memcpy(pMessage->pData, &pData, sizeof(unsigned int));
#endif
}

// getting the pointer out
{
#if 0
    unsigned char *pData; (unsigned char *)(*((unsigned int *)pMessage->pData));
#else
    unsigned char *pData;
    memcpy(&pData, pMessage->pData, sizeof(int));
#endif
}

Ответы [ 3 ]

3 голосов
/ 16 февраля 2011

Я подозреваю, что это проблема выравнивания, и либо GCC, либо процессор пытается компенсировать это.Структура определяется следующим образом:

typedef struct {
    long mtype;
    unsigned short uRespQueue;
    unsigned short uID;
    unsigned short uLen;
    unsigned char pData[8000];
} message_t;

При условии нормальных ограничений выравнивания и 32-разрядного процессора смещения каждого поля:

mtype         0   (alignment 4)
uRespQueue    4   (alignment 2)
uID           6   (alignment 2)
uLen          8   (alignment 2)
pData         10  (alignment 1)

На всех, кроме самых последних версийпроцессор ARM, доступ к памяти должен быть должен быть выровнен на процессоре ARM, и при приведении:

*((unsigned int *)pMessage->pData) = (unsigned int)pData;

вы пытаетесь записать 32-разрядное значение на выровненный адрес.Чтобы исправить выравнивание, кажется, что адрес урезал младшие биты адреса, чтобы иметь правильное выравнивание.При этом произошло совпадение с полем uLen, вызвавшим проблему.

Чтобы справиться с этим правильно, необходимо убедиться, что вы записали значение в правильно выровненный адрес.Либо сместите указатель, чтобы выровнять его, либо убедитесь, что pData выровнен, чтобы иметь возможность обрабатывать 32-битные данные.Я бы переопределил структуру, чтобы выровнять элемент pData для 32-битного доступа.

typedef struct {
    long mtype;
    unsigned short uRespQueue;
    unsigned short uID;
    unsigned short uLen;
    union { /* this will add 2-bytes of padding */
        unsigned char *pData;
        unsigned char  rgData[8000];
    };
} message_t;

Структура должна по-прежнему занимать такое же количество байтов, поскольку имеет 4-байтовое выравнивание из-за mtype field.

Тогда вы сможете получить доступ к указателю:

unsigned char *pData = ...;
/* setting the pointer */
pMessage->pData = pData;

/* getting the pointer */
pData = pMessage->pData;
0 голосов
/ 31 мая 2012

Дело в том, что здесь есть код «int header = ( ((int ) (txUserPtr) - 4))». Иллюстрация UserTypes и приведение указателей структуры очень помогают!

0 голосов
/ 16 февраля 2011

Это очень неприятная вещь (вещь, которая составлена).Вы пытаетесь в основном взломать код, и вместо того, чтобы использовать копию данных в сообщении (в предоставленных для него 8000 байт), вы пытаетесь поместить указатель и передать его через IPC.

Основной проблемой является разделение памяти между процессами.Кто знает, что происходит с этим указателем после его отправки?Кто знает, что происходит с данными, на которые он указывает?Это очень плохой навык - отправлять указатель на данные, которые не находятся под вашим контролем (то есть: не защищены / должным образом не переданы).

Еще одна вещь, которая может произойти, и, вероятно, это то, о чем вы на самом деле говорите, это выравнивание.Массив имеет значение char, предыдущий член в структуре - short, компилятор может попытаться их упаковать.Передача от char[] до int * означает, что вы берете область памяти и представляете ее как нечто иное, не сообщая компилятору.Вы топаете над uLen актерами.

memcopy - правильный способ сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...