Я не вижу в этом ничего плохого.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
/* Reference:
(0 offset) uint32_t size;
(+4 offset) uint32_t elementSize;
(+8 offset) uint32_t lastIndex;
(+12 offset) void* data
*/
void* create_pinned_array(uint32_t elementSize, uint32_t numberOfElements, size_t sizeOfData, void* data)
{
uint32_t size = sizeOfData + 12;
void* memory = malloc(size);
memset(memory, size, 4); // size
memset(memory + 4, elementSize, 4); // elementSize
memset(memory + 8, numberOfElements-1, 4); // lastIndex
memcpy(memory + 12, data, sizeOfData); // actual data
return memory;
}
int main(void)
{
int randomList[5] = { 1, 6, 2, 9, 8 };
void* myIntegers = create_pinned_array(sizeof(int), 5, sizeof(randomList), randomList);
FILE* testfp = fopen("testfile.bin", "wb");
fwrite(myIntegers, sizeof(myIntegers), 1, testfp);
fclose(testfp);
free(myIntegers);
return 0;
}
Каждый раз, когда я проверяю с помощью xxd, вместо упорядоченного двоичного файла я получаю ненужные данные, которые меняются каждый раз, когда я запускаю программу.
Это делает дикие предположения о форме байтов этих значений, которые, я надеюсь, оправданы.
memset(memory, size, 4);?!?!?! Вы понимаете, что memset() устанавливает для каждого байта того, что устанавливается, одно и то же значение байта?
И, пожалуйста, прочитайте как Гибкий элемент массива в C-структуре , так и Как правильно использовать гибкий элемент массива?
@AndrewHenle, я не могу поверить, что совершил эту ошибку. Использование memcpy вместо этого исправило это. Спасибо
@Hexa Простое присвоение с использованием кода, такого как memory->size = size;, предпочтительнее. Использование memcpy() для смещения будет неверным, если изменится тип memory->size (например, на size_t в 64-битной системе) или изменится макет структуры.
@AndrewHenle да, но я пытаюсь создать контейнер, не зависящий от типа данных, вроде вектора в С++, поэтому использование struct api не сработает.





Похоже, вы ошиблись с sizeof.
sizeof(myIntegers)
Возвращает размер пустого указателя, хотя в этом случае кажется, что create_pinned_array вернул блок памяти размером 32 байта (при условии, что int равен 4 байтам). Предполагая 64-битную машину, это означает, что вы записываете первые 8 байтов ваших данных.
Ваша функция create_pinned_array также должна проверять успешность возврата malloc, прежде чем приступить к работе с результатами.
Вы используете memset, когда хотите использовать memcpy.
memset(ptr, value, N)
Заполняет байты от ptr до ptr+n символом value.
memcpy(ptr, src, N) копирует N байт из src в ptr.
Вместо этого:
memset(memory, size, 4); // size
memset(memory + 4, elementSize, 4); // elementSize
memset(memory + 8, numberOfElements-1, 4); // lastIndex
memcpy(memory + 12, data, sizeOfData); // actual data
Этот:
uitn32_t lastIndex = numberOfElements-1;
memcpy(memory, &size, 4); // size
memcpy(memory + 4, &elementSize, 4);
memcpy(memory + 8, &lastIndex, 4);
memcpy(memory + 12, data, sizeOfData);
Или вы можете попробовать это, что должно быть в порядке, поскольку память malloc будет выровнена. (На некоторых платформах, отличных от Intel, выравнивание важно, если указатель не находится на 32-битной границе)
uint32_t* header = (uint32_t*)memory;
header[0] = size;
header[1] = elementSize;
header[2] = nmberOfElements-1;
memcpy(memory + 12, data, sizeOfData);
Это может быть не единственная ошибка.
sizeof(myIntegers)— это размер указателя, а не блока памяти.