在C中返回一个指向常量对象的void指针

时间:2009-02-19 20:53:21

标签: c const void-pointers

我正在编写一个访问函数,它返回一个指向内部缓冲区的指针,我想向我的函数用户提示他们不应该更新指向的对象。一个非常人为的例子是:

void myAccessFunc(bool string, void* p, size_t* len)
{
  static const char* s = "aha!";
  static const int i = 123;

  if (string) {
     *(char**)p = &s;
     *len = strlen(s);
  }
  else {
     *(int**)p = &i;
     *len = sizeof(i);
  }
}

char* s;
size_t bytes;
myAccessFunc(true,&s, &bytes);
printf("Got '%s'\n", s);

是的,我知道这看起来很不错。

我想要阻止的是:

char* s;
size_t bytes;
myAccessFunc(true,&s,&bytes);
s[4] = '?';

我知道我不能完全阻止它,但我至少喜欢编译器警告提示用户他们不应该这样做。如果他们投了我的指针,那就是他们的问题。有没有const和void的组合和*会这样做?我试过像:

void myAccessFunc(bool string, const void** p, size_t* len);

但它似乎消除了指针的无效性,因此调用者必须这样做:

const void* p;
size_t bytes;
myAccessFunc(true, &p, &bytes);

const char* s;
size_t bytes;
myAccessFunc(true, (const void**)&s, &bytes);

并且无法做到:

const int * ip;
const char* s;
size_t bytes;
myAccessFunc(true, &s, &bytes);
myAccessFunc(false, &i, &bytes);

我终于到了:

const void* myAccessFunc(bool string, size_t* len);

如果用户执行:

char* p = myAcccessFunc(true,&bytes);

编译器(至少是GCC)确实抱怨丢弃限定符。

7 个答案:

答案 0 :(得分:10)

最好做一些事情:

const void * myAccessFunc();

在返回指向内部的指针的地方,这比将其作为out参数传递更自然。

如果您将其作为out参数传递,则需要:

void myAccessFunc(const void **p);

阻止他们意外地这样做:

void *p;  /* error: must be 'const void *p;' */
myAccessFunc(&p);

答案 1 :(得分:3)

你可以做两件事:

  • 返回const void *
  • 为您的API撰写一些文档,告知用户不要修改返回值

话虽如此,任何决定尝试用这样的指针进行捣乱的API用户都应该得到它们:P。

答案 2 :(得分:2)

预防是不可能的,因为你可以抛弃常量。如果你使你的函数参数为const,你将不得不在函数内部将它抛弃。你也会对任何使用你的功能的人说谎,并且会引起各种有趣的错误。

您可以尝试返回指针。那么你至少不会违反你自己的const。在这种情况下,这可能不合适。

答案 3 :(得分:2)

返回指针是最好的,但是如果你绝对需要使它成为out参数,你可以使用结构作为中介:

typedef struct _ptr_holder {
   const void* ptr;
} ptr_holder;

void myAccessFunc( bool string, ptr_holder* ptr ) {
...
}

ptr_holder s;
myAccessFunc(true,&s);
printf("Got '%s'\n", s.ptr);

这很好,但它应该可以解决问题

答案 4 :(得分:1)

所以你想防止通过你返回的指针修改?试试这个:

const void* myAccessFunc(bool string);

这有什么问题?如果您要对有效答案进行投票,请发表评论。

答案 5 :(得分:1)

如果您正在编写一个不希望公开某些内部数据结构的C库,那么最好使用额外的路径并使用未指定的struct typedef隐藏实现。这也称为opaque types

示例:

my_interface.h

 #ifndef __MYINTERFACE_H__
 #define __MYINTERFACE_H__

 /* The unspecified struct statement */
 typedef struct s_my_data t_my_data;

 t_my_data  *new_my_data(int someInitializer);
 void        free_my_data(t_my_data *data);
 int         enter_my_data(t_my_data *data, int someDataToEnter);

 const char *return_str_my_data(t_my_data *data);

 #endif /* __MYINTERFACE_H__ */



my_interface.c

 #include <my_interface.h>

 /* Keep struct in .c file */
 struct s_my_data {
     int    length;
     char  *string;
 };

 t_my_data *new_my_data(int someInitializer)
 {
     /* the exercise */
 }

 void free_my_data(t_my_data *data)
 {
     /* the exercise */
 }

 int enter_my_data(t_my_data *data, int someDataToEnter)
 {
     /* the exercise */
 }

 const char *return_str_my_data(t_my_data *data)
 {
     /* the exercise */
 }

答案 6 :(得分:0)

这是C还是C ++? 为什么在int情况下你将指针传递给静态const? 界面很可疑。

重载并摆脱界面中的布尔值:

void myAccessFunc( const char* * const p, size_t* len){
   *p = "blahblahblah";
   *len = 12;
}

void myAccessFunc( const int* * const ppI, size_t* len){
   static const int i = 123;
   *ppI = &i;
   *len = 4;
}

也摆脱了测试。由于用户知道原始功能的真或假,他知道使用哪一个。强打字是你的朋友。删除类型和指针不一致的错误类...

BTW传递这样的控制标志与过载是不可取的,尤其是在小方法中。