Разыменование общего указателя с использованием типа данных - PullRequest
0 голосов
/ 22 ноября 2018

Мой код выглядит следующим образом

typedef unsigned short  uint16;

struct STR
{
    const int x;
    const uint16 y;
    const int z;
    void* sptr;
};

struct STR s2[2] = 
{
    {1, 4, 6, {&s2[0].x, &s2[0].y, &s2[0].z}},
    {10,40, 60, {&s2[1].x, &s2[1].y, &s2[1].z}}
};

int main()
{
    void* tptr = s2[0].sptr;
    printf("%d %d %d", *((int*)tptr), *( (uint16*)tptr+1 ), *((int*)tptr+2));
    return 0;
}

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

Ожидаемый результат: 1 4 6

Но если я использую

printf("%d %d %d", *((int*)tptr), *( (uint16*)tptr+1 ), *((int*)tptr+2));

, я получаю вывод как 1 0 6. ЗдесьЯ использовал для определения типа тип данных uint16.

Вместо этого, если я использую

printf("%d %d %d", *((int*)tptr), *( (int*)tptr+1 ), *((int*)tptr+2));

, я получаю правильный вывод как 1 4 6. Почему тип uint16 не может разыменоватьсяуказатель и получение 0 значения.Пожалуйста, кто-нибудь поможет и предоставит идеи для решения этой проблемы.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Спасибо всем за ваши комментарии.Чтобы решить эту неопределенную проблему поведения в матрице памяти структуры.Я заменил указатель void в структуре на массив указателей и доступ к нему с помощью двойного указателя, и теперь это работает нормально.Но это может занять немного больше памяти.Новый код как этот

typedef unsigned short  uint16;

struct STR
{
    const int x;
    const uint16 y;
    const int z;
    void* sptr[3];
};

struct STR s2[2] = 
{
    {1, 4, 6, {&s2[0].x, &s2[0].y, &s2[0].z}},
    {10,40, 60, {&s2[1].x, &s2[1].y, &s2[1].z}}
};

int main()
{
    void** tptr = s2[0].sptr;
    printf("%d %d %d", *((int*)*tptr), *( (uint16*)*(tptr+1)), *((int*)*(tptr+2)));
    return 0;
}

//Output: 1  4  6
0 голосов
/ 22 ноября 2018

Здесь я вижу несколько проблем.Во-первых, вы не можете объявлять подобные структуры.Переменная void * является указателем.Вы пытаетесь определить всю структуру на своем месте и используете для этого неправильный синтаксис.Я удивлен, что компилятор не отклонил код.

Вам, очевидно, нужно будет определить структуру, которая также принимает 3 целочисленных указателя для значений.Если вы действительно хотите объявить все сразу, и четвертый элемент должен быть указателем, вы можете использовать составной литерал следующим образом:

#pragma GCC diagnostic ignored "-Wmissing-braces"
struct other_struct {
        const int *x;
        const uint16 *y;
        const int *z;
};
struct STR s2[2] = {
    {1, 4, 6, (struct other_struct[1]){&s2[0].x, &s2[0].y, &s2[0].z}},
    {10,40, 60, (struct other_struct[1]){&s2[1].x, &s2[1].y, &s2[1].z}}
};

Обратите внимание, что компилятор может отклонить соединениебуквально в области видимости файла (я думаю, что MSCV делает).

Вы также, похоже, стали жертвой заполнения.Компилятор всегда будет пытаться выровнять данные в структуре по кратному размеру слова вашей машины (8 байт для 64-битной), если вы явно не скажете этого не делать.Кроме того, вещи часто выстраиваются по крайней мере до 4-байтовой границы (размер целого числа).Поскольку то, что вы делаете, является совершенно неопределенным поведением, ваш компилятор просто попытался расширить структуру, задав каждому элементу размер целого числа.Когда вы пытаетесь просмотреть следующий int16 в своей структуре, вы смотрите вперед на 2 байта, но следующее значение фактически на 4 байта вперед, поэтому вы получаете значение 0. Это также объясняет, почему это работает, когда вы приводите к int *.

РЕДАКТИРОВАТЬ: На самом деле я сделал ошибку выше.Сожалею.Ваш код не работал должным образом не обязательно из-за заполнения, а из-за того, как вы написали арифметику указателей .Попытка найти элементы в исходном массиве таким способом на самом деле невозможна, и, конечно, в любом случае неопределенное поведение.

...