void** параметр вызывается с фиксированным значением массива
У меня есть массив фиксированного размера, объявленный:
int vals[25];
И я хотел бы отправить массив в функцию, которая будет присваивать значения vals:
bool FetchValueArray(char* source, char* name, char* typeFormat, int count, void** destination)
{
int i;
char *t;
t=strstr(source,name);
if (t)
if (destination != NULL)
{
for (i = 0;i < count;i++)
sscanf(t,typeFormat,destination[i]);
return true;
}
return false;
}
По сути, это будет читать все после определенной строки поиска. Например:
FetchValueArray(source,"CONFIG=","%d",15,vals);
Где "CONFIG=" в виде простого текста, за которым следуют 15 числовых значений, разделенных табуляцией.
Здесь есть кое-что, что я далек от того, чтобы сходить с ума по поводу косвенных массивов и фиксированных аизированных массивов, поэтому я хотел бы знать, можно ли отправлять массив фиксированного размера в качестве параметра как void** (даже если есть скачок веры в то, что размер массив будет уважаться. Другая проблема.)
TL; Dr версия
int vals[25];
bool foo(int size,void** d);
foo(25,vals);
Почему это не разрешено?
1 ответ
Массивы распадаются на указатели на их первые элементы, и указатели на любой тип могут быть неявно приведены к void*
, Во-вторых, чтобы доступ к массиву работал правильно, FetchValueArray
нужно знать, насколько велик каждый элемент массива. Вы пытаетесь передать void**
, который является указателем на void*
таким образом, доступ к массиву обрабатывает каждый элемент, как если бы он имел размер void*
, что неправильно - ваши элементы массива имеют размер int
, который не обязательно совпадает с размером void*
,
Так void**
неправильно. Вам вместо этого нужно пройти в void*
, что означает "указатель на неизвестный тип". Вы не можете использовать индексирование массива на void*
, так как компилятор не знает размер базового указательного типа. Вы должны помочь этому. Например:
bool FetchValueArray(char* source, char* name, char* typeFormat, int count, void* destination, size_t destElementSize)
{
...
sscanf(t, typeFormat, (char*)destination + destElementSize * i);
...
}
...
FetchValueArray(source, "CONFIG=", "%d", 15, vals, sizeof(vals[0]));
Здесь мы выполняем индексацию массива вручную - мы приводим void*
в char*
, который имеет известный указываемый размер (1 байт), а затем выполняет смещение массива путем умножения на размер каждого элемента. Результатом является указатель на правильную область памяти, которая sscanf
надеется.
Но будьте здесь очень осторожны - я думаю, вы должны пересмотреть свой дизайн. Компилятор не знает семантику вашей функции, поэтому он не может проверить, что вы передаете правильные аргументы. Очень легко вставить случайную уязвимость безопасности, не осознавая этого здесь. Подумайте, может ли вам быть лучше с другим дизайном, который компилятор может проверить более тщательно.