2016-04-14 4 views
2

У меня есть функция в C, которая должна получать указатель на массив (с неопределенным типом).Void ** как параметр требует лить

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

К сожалению, проблема связана с компилятором (передается аргумент 1 из 'f' из несовместимого типа указателя). Если я игнорирую предупреждение и пытаюсь выполнить программу, все работает так, как ожидалось.

Единственный способ избавиться от предупреждения - это бросить все, что я пытаюсь передать функции void **.

Почему C ведет себя так? И есть ли лучший способ решить предупреждение?

PS: Мне нужно скомпилировать с помощью GCC с флагами -std = gnu89 -pedantic -Wall

Пример

int f(void** param){ return 1; } 

int main(){ 
    int *arr = malloc(sizeof(int) * 20); 
    int i; 
    for(i=0; i < 20; i++) arr[i] = i; 
    f(&arr); 
} 
+2

'int f (void ** param) {return 1; } '->' int f (void * param) {return 1; } ', не используйте' ** ', вы можете прочитать указатель на массив, используя один указатель (' void * ') –

+1

@AlterMann Как мне изменить значение распределения для' arr'? –

+0

@SouravGhosh Это именно то, что я должен выполнить. – Spotlight

ответ

3

Указатель на что-нибудь типа void*, и компилятор не будет жалуйтесь на конверсии этого типа. Но void** не является указателем на что-либо, это указатель на массив указателей на что угодно, что сильно отличается от указателя на массив указателей на целые числа, поэтому компилятор жалуется. Итак, чтобы решить предупреждение, да, вам нужно будет явно указать.

+1

Спасибо за проработку, но как это ответить на вопрос? –

+1

Один из вопросов был, почему C ведет себя так? – atturri

+0

* "это указатель на массив указателей на что угодно" *. Нет, это будет 'void * (*) []'. 'void **' является указателем на указатель на что угодно. – user694733

1

Хотя void * является «общим указателем» в C, void ** не является «общим указателем на указатель». Вместо этого это не что иное, как «» указатель на void *, общий указатель ».

В вашем случае int ** преобразуется неявно в void **, что не является общим. Поскольку void ** не может содержать все переменные указателя (таким образом, несовместимые с int **), компилятор выводит предупреждение.

Вот предупреждение генерируется звоном:

main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of 
     type 'void **' [-Wincompatible-pointer-types] 
    f(&arr); 
     ^~~~ 
main.c:1:14: note: passing argument to parameter 'param' here 
int f(void** param){ return 1; } 

Чтобы устранить это предупреждение, вы можете иметь int f(void* param); и брось param к int ** внутри функции. Там не будет никакого предупреждения, поскольку void * может быть использован для хранения любого указателя (Цитируется из N1570):

6.3.2.3 Указателей

1 Указатель к мочеиспусканию может быть преобразован в или из указателя на любой тип объекта. Указатель на любой тип объекта может быть преобразован в указатель на void и обратно; результат сравнивается с исходным указателем .

+0

Нет никакого неявного преобразования из 'int **' в 'void **', код OP является нарушением ограничения –

+0

Этот код является нарушением ограничения, потому что нет такой вещи, как неявное преобразование между 'int **' и 'void ** ' –

+0

@MM Но кажется, что это разрешено стандартом, см .: http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7 –

2

кажется, что вы хотите изменить адрес данных (не значение) внутри функции, вы не можете сделать это прямо с void *, потому что вы не можете использовать арифметику с void *, но вы можете передать размер первого элемента и кусок байтов (char *), предположим, что вы хотите изменить адрес arr к arr + 1 (второй элемент массива) внутри функции:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void f(void *ptr, size_t size) 
{ 
    // char *p = *ptr; Wrong, you can't dereference a void * without a cast 
    char *p = *(char **)ptr; /* pointer to address of ptr */ 

    memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */ 
} 

int main(void) 
{ 
    int *arr = malloc(sizeof(int) * 20); 
    int i; 
    for (i = 0; i < 20; i++) arr[i] = i; 
    f(&arr, sizeof arr[0]); 
    printf("%d\n", arr[0]); 
    return 0; 
} 

Выход:

1 
Смежные вопросы