void ** параметр вызывается с фиксированным значением массива - PullRequest
0 голосов
/ 04 октября 2011

У меня объявлен массив фиксированного размера:

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 Ответ

2 голосов
/ 04 октября 2011

Массивы распадаются на указатели на свои первые элементы, и указатели на любой тип могут быть неявно приведены к 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.

Будьте здесь очень осторожны - я думаю, вам следует пересмотреть свой дизайн. Компилятор не знает семантику вашей функции, поэтому он не может проверить, что вы передаете правильные аргументы. Очень легко вставить случайную уязвимость безопасности, не осознавая этого здесь. Подумайте, может быть, вам лучше использовать другой дизайн, который компилятор сможет проверить более тщательно.

...