const 双指针的惯用 C
我知道在 C 中你不能隐式转换,例如,将 char**
转换为 const char**
(参见 C-常见问题解答,所以问题 1,所以问题 2)。
另一方面,如果我看到这样声明的函数:
void foo(char** ppData);
我必须假设该函数可能会更改传入的数据。 因此,如果我正在编写一个不会更改数据的函数,我认为最好声明:
void foo(const char** ppData);
甚至:
void foo(const char * const * ppData);
但这会使该函数的用户处于尴尬的境地。 他们可能有:
int main(int argc, char** argv)
{
foo(argv); // Oh no, compiler error (or warning)
...
}
为了干净地调用我的函数,他们需要插入强制转换。
我主要来自 C++ 背景,由于 C++ 更深入的 const 规则,这不是什么问题。
C 中惯用的解决方案是什么?
将 foo 声明为采用
char**
,并仅记录它不会更改其输入的事实?这看起来有点恶心,尤其是。因为它会惩罚那些可能想要传递 const char** 的用户(现在他们必须放弃 const 性)强制用户进行转换他们的输入,添加常量。
还有什么吗?
I am aware that in C you can't implicitly convert, for instance, char**
to const char**
(c.f. C-Faq, SO question 1, SO Question 2).
On the other hand, if I see a function declared like so:
void foo(char** ppData);
I must assume the function may change the data passed in.
Therefore, if I am writing a function that will not change the data, it is better, in my opinion, to declare:
void foo(const char** ppData);
or even:
void foo(const char * const * ppData);
But that puts the users of the function in an awkward position.
They might have:
int main(int argc, char** argv)
{
foo(argv); // Oh no, compiler error (or warning)
...
}
And in order to cleanly call my function, they would need to insert a cast.
I come from a mostly C++ background, where this is less of an issue due to C++'s more in-depth const rules.
What is the idiomatic solution in C?
Declare foo as taking a
char**
, and just document the fact that it won't change its inputs? That seems a bit gross, esp. since it punishes users who might have aconst char**
that they want to pass it (now they have to cast away const-ness)Force users to cast their input, adding const-ness.
Something else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
尽管您已经接受了答案,但我想选择 3) 即宏。您可以以这样的方式编写这些函数,即函数的用户只需编写一个调用
foo(x);
,其中 x 可以是const
限定的,也可以不是。这个想法是让一个宏CASTIT
执行转换并检查参数是否为有效类型,另一个宏是用户界面:CASTIT
宏看起来是一个有点复杂,但它所做的只是首先检查X[0]
的赋值是否与char const*
兼容。它使用复合文字来实现这一点。然后将其隐藏在sizeof
中,以确保实际上永远不会创建复合文字,并且该测试不会评估X
。接下来是简单的演员阵容,但这本身就太危险了。
正如您在
main
中的示例所看到的,这准确地检测到了错误的情况。很多这样的事情都可以通过宏来实现。我最近用
const< 编写了一个复杂的示例 /code>-限定数组。
Although you already have accepted an answer, I'd like to go for 3) namely macros. You can write these in a way that the user of your function will just write a call
foo(x);
where x can beconst
-qualified or not. The idea would to have one macroCASTIT
that does the cast and checks if the argument is of a valid type, and another that is the user interface:The
CASTIT
macro looks a bit complicated, but all it does is to first check ifX[0]
is assignment compatible withchar const*
. It uses a compound literal for that. This then is hidden inside asizeof
to ensure that actually the compound literal is never created and also thatX
is not evaluated by that test.Then follows a plain cast, but which by itself would be too dangerous.
As you can see by the examples in the
main
this exactly detects the erroneous cases.A lot of that stuff is possible with macros. I recently cooked up a complicated example with
const
-qualified arrays.2 比 1 好。不过 1 很常见,因为大量 C 代码根本不使用 const。因此,如果您正在为新系统编写新代码,请使用 2。如果您正在为很少使用 const 的现有系统编写维护代码,请使用 1。
2 is better than 1. 1 is pretty common though, since huge volumes of C code don't use const at all. So if you're writing new code for a new system, use 2. If you're writing maintenance code for an existing system where const is a rarity, use 1.
选择选项 2。选项 1 具有您提到的缺点,并且类型安全性较差。
如果我看到一个带有
char **
参数的函数,并且我有一个char *const *
或类似的参数,我会制作一个副本并传递它,只需以防万一。Go with option 2. Option 1 has the disadvantage that you mentioned and is less type-safe.
If I saw a function that takes a
char **
argument and I've got achar *const *
or similar, I'd make a copy and pass that, just in case.现代 (C11+) 方式使用
_Generic
来保留类型安全和函数指针:Modern (C11+) way using
_Generic
to preserve type-safety and function pointers: