返回一个指向 C 中常量对象的 void 指针
-
05-09-2019 - |
题
我正在编写一个访问函数,它返回一个指向内部缓冲区的指针,我想提示我的函数的用户他们不应该更新指向的对象。一个非常人为的例子是:
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)确实抱怨丢弃限定符。
解决方案
这将是最好做的是这样的:
const void * myAccessFunc();
你在哪里返回指针到内部,这比将它作为输出参数更自然一点。
如果你把它作为一个输出参数,你会想:
void myAccessFunc(const void **p);
以防止它们意外地这样做:
void *p; /* error: must be 'const void *p;' */
myAccessFunc(&p);
其他提示
您可以做两件事:
- 返回一个 const void*
- 为您的 API 编写一些文档,告诉用户不要修改返回值
话虽如此,任何决定尝试使用这样的指针的 API 用户都是值得的:P。
防止是不可能的,因为你可以抛弃常量性。如果你让你的函数参数常量,你就必须自己投它拿走里面的功能。你想也可以用你的函数说谎的人,可能会引起各种有趣的错误。
您可以尝试返回一个指针来代替。然后,你至少不会违反自己的常量。这可能不是在这种情况下,虽然合适的。
返回一个指针将是最好的,但如果你的绝对的需要使它的输出参数,你可以使用一个结构作为中介:
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);
这是做作,但它应该做的伎俩
所以,你要防止通过返回指针的修改?尝试这样:
const void* myAccessFunc(bool string);
什么是错的呢?如果你要否决一个有效的答案,请发表评论。的
如果你正在写一个C库,你不希望暴露了一些内部数据结构也可以是好去一个额外的路线的和隐藏了不确定结构的typedef实现。这也被称为一个不透明类型
示例:
在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 */
}
这是C或C ++? 在INT情况下你为什么要传递指针静态常量? 该接口是可疑的。
过载和接口摆脱布尔的:
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;
}
摆脱了测试的太。由于用户知道真或假的原有功能,他知道使用哪一个。强类型是你的朋友。摆脱了类,其中类型和指针不一致错误的...
顺便说一下,例如通过控制标志与重载是不希望的,特别适合在小型的方法。