2015-10-12 52 views
0

如何在编译器检查以确保参数传递是指针指针时正确消除此警告?消除void **与any_struct_t **警告

void somefunc (void **elements) 
{ 
    // This function works on any array type 
    // Maybe it prints pointer addresses 
    void **pp; 
    for (pp = elements; *pp; pp ++) 
     printf ("address: %x\n", *pp); 
} 

int main (const char *cmdline) 
{ 
    typedef struct { 
     int a, b, c; 
    } any_struct_t; 

    any_struct_t *group[25] = {0}; // (any_struct_t **) 
    group[0] = malloc (sizeof(any_struct_t)); 
    somefunc(group); // <--- WARNING (any_struct_t **) vs. (void **) 
    getchar(); 
    exit (0); 
} 

是否有“双空”类型的指针或可在这里用来得到正确消除这个警告的一些超级晦涩Ç招:

I want this warning to go away via code: 
warning: passing argument 1 of 'somefunc' from incompatible pointer type 
expected 'void **' but argument is of type 'any_struct_t **' 

函数想要一个指向指针的指针,它不关心它是什么类型的指针。

我可以通过强制转换(void *)来消除警告,但编译器不再检查它是否是指向指针的指针。

+0

是什么原因,为什么你有一个指针数组,每个指针指向到一个单一的结构?是否有一个原因,你为什么不能有一个结构数组呢? – Lundin

+0

编译器无论如何都没有真正检查指向指针的指针。 – Peter

+0

有没有办法让它这样做? –

回答

0

如果传递的参数不是(至少)指针指针,至少会产生编译时错误。这不是完全的想法,但至少有类型检查。

void _somefunc (void **elements) 
{ 
    // This function works on any array type 
    // Maybe it prints pointer addresses 
    void **pp; 
    for (pp = elements; *pp; pp ++) 
     printf ("address: %p\n", *pp); 
} 

// ENSURE AT LEAST A POINTER TO A POINTER IN DEBUG BUILDS, WILL CAUSE ERROR IF NOT. 
// error: invalid type argument of unary '*' 
#ifdef DEBUG 
    // Ensure at least a pointer to a pointer. Compile-time error if not. 
    #define somefunc(x) _somefunc ((void **)x + sizeof(**x) - sizeof(**x)) 
#else 
    #define somefunc(x) _somefunc (((void **)x) // No warnings in release 
#endif 
1

void*是唯一的通用指针类型,它每隔一个指针类型可以得到隐式转换到/从。但这并不适用于void**,因为正式的void**不需要与x**具有相同的实现。

但是,正如您所指出的那样,您可以简单地投射到void*并且警告将消失。理论上,这不会是便携式的。在实践中,我非常怀疑你会遇到任何问题。

因此,如果你对文字类型安全性有着迂回的关注,那么你不会仅仅投掷到void*并继续前进的唯一原因。如果你是,你应该写一个函数来处理每个单独的指针类型。

例如,在C11,你可以用_Generic关键字做到这一点有点优雅:

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


typedef struct { 
    int a, b, c; 
} any_struct_t; 


#define some_func(ptr) \ 
_Generic((ptr), \ 
      any_struct_t**: some_any_struct)(ptr) 

void some_any_struct (any_struct_t** pp) 
{ 
    for(; *pp != NULL; pp++) 
    { 
    printf ("address: %p\n", (void*)*pp); 
    } 
} 


int main(void) 
{ 
    any_struct_t* array [4] = {0}; 

    array[0] = malloc(10*sizeof(any_struct_t)); 
    array[1] = malloc(1*sizeof(any_struct_t)); 
    array[2] = malloc(5*sizeof(any_struct_t)); 
    array[3] = NULL; 

    some_func(array); 

    void* void_array[3]; 
    some_func(void_array); // will cause compiler error, because void** is not supported 
} 
+0

我将不得不调查此_Generic关键字。但是,是的,某种类型的安全性很重要,因为我有一些函数需要数组(any_type_t **),有些函数修改数组地址本身的3x指针(any_type_t ***)。 –

+0

@ B.Nadolson你为什么要修改数组地址?有一条一般的经验法则说如果你发现自己需要三颗星,你需要重新考虑你的程序设计。所有这些听起来不必要的复杂,如果你制作一个通用的ADT来封装所有的分配,间接和索引,你可能会简化很多事情。 – Lundin

+0

动态矢量数组带有一个指针块,提供(罕见的)扩展。链接列表,动态数组,块分配和用于快速索引和快速排序的固定大小列表的组合提供了静态分配,并且可以通过单线启动,如char ** strings = string_vector_from_list(“apple”,“orange “,”banana“,NULL); vector_resize(字符串,25)/ *升至25 * /;可以添加,移动,排序,删除。不限于任何数据类型。 your_struct_t ** something = vector_array_alloc(something,25/* num items * /);简单,快速,功能强大,灵活。但需要进行类型检查。 –

0
void somefunc (void **elements) 
{ 
// This function works on any array type 
// Maybe it prints pointer addresses 
any_struct_t **pp; 
for (pp = (any_struct_t *)elements; *pp; pp ++) 
    printf ("address: %x\n", *pp); 
} 

int main (const char *cmdline) 
{ 
    typedef struct { 
    int a, b, c; 
} any_struct_t; 

void *group[25] = {0}; // (any_struct_t **) 
group[0] = malloc (sizeof(any_struct_t)); 
somefunc(group); // <--- WARNING (any_struct_t **) vs. (void **) 
getchar(); 
exit (0); 

}