Странное поведение при использовании гибкого члена массива - PullRequest
1 голос
/ 27 февраля 2012

Я попытался заменить элемент void * структуры на член гибкого массива, используя более приемлемую идиому:

typedef struct Entry {
    int counter;
    //void* block2; // This used to be what I had
    unsigned char block[1];
}

Затем я добавляю записи в непрерывный блок памяти:

void *memPtr = mmap(NULL, someSize*1024, PROT_READ|PROT_WRITE, 
                        MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

как таковой:

int number = 0;

int AddEntry(void *data) {
   Entry *entry;
   entry = malloc(sizeof(Entry) + ((SECTOR_SIZE-1) * sizeof(unsigned char));
   entry->counter = 1;
   memcpy(entry->block, data, SECTOR_SIZE);

   // make sure number doesn't overflow space, etc...
   memcpy(&memPtr[number], entry, sizeof(Entry) + ((SECTOR_SIZE-1) * sizeof(unsigned char));
   number++;
   return 0;
}

Проблема заключается в распаковке этих данных, когда они мне понадобятся.Например, если я сделаю:

void * returnBlock(int i) {
    Entry * entry  = &memPtr[i];
    printf("Entry counter is %d\n", entry->counter); // returns 1, reliably
    return entry->block; // Gives me gibberish but not if I uncomment void* block2.
}

Есть ли причина, по которой это может быть?Я не обязательно думаю, что я где-то топаю, и это работало с подходом void *. Странно то, что, если я помещаю пустую пустоту обратно в структуру, она работает .Он не работает, если я вставляю фиктивный int.

Редактировать: на самом деле, он также не работает, если number в AddEntry не равно 0. На что я наступаю, если что-нибудь?

1 Ответ

2 голосов
/ 27 февраля 2012

Ваша проблема здесь:

&memPtr[number]

Поскольку memPtr - это указатель void *, это фактически не разрешено в C. Некоторые компиляторы допускают арифметику для void * указателей в качестве расширения языка - однако они обрабатывают это так, как если бы это был указатель char *.

Это означает, что &memPtr[number], вероятно, индексирует только number байт в ваш блок памяти - таким образом, вторая скопированная структура Entry будет перекрывать первую и т. Д.

Похоже, ваша строка размещения принимает 1024 байта на Entry (если someSize - это число Entry структур), поэтому вам, вероятно, нужно что-то вроде:

((char *)memPtr + number * 1024)

(и аналогично функции returnBlock()).

Однако, если вы сделаете это, вы заметите, что нет смысла использовать член гибкого массива - поскольку вы создаете непрерывный массив этих структур и не имеете отдельного индекса, вы должны предположить, что каждый один фиксированный размер. Это означает, что вы можете также сделать каждый фиксированный размер:

typedef struct Entry {
    int counter;
    unsigned char block[1024 - sizeof counter];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...