qsort 函数指针的类型转换
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static int cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int main(int argc, char *argv[])
{
int j;
assert(argc > 1);
qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);
for (j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}
我对这部分感到困惑:
return strcmp(* (char * const *) p1, * (char * const *) p2);
他们为什么这样做?为什么他们不这样做:(const char**)
或 (const char * const*)
?如果我们对 (const char**)
取消引用一次,难道我们不会得到一个指向 const char 的指针吗?取消引用第二个,我们不是得到一个指向 const char 的 const 指针吗?这两个似乎都符合 strcmp()
的要求:两个指向 const 字符的指针。手册页似乎为我们提供了指向非常量事物的常量指针,这似乎不是 strcmp()
声明所要求的。即使合法,给函数提供不适合其参数的东西似乎也不是一个好主意。我错过了什么吗?
最后,为什么下面的代码至少不会生成一个错误警告:
auto const char * const ptr3 = *(const char **) ptr1; //where ptr1 is
of the form int foo(const void * ptr).
取消引用 ptr1
一次会给我们一个指向 const char 的指针,但它本身不是 const。然而,ptr3
是 const。那么为什么编译器不生成警告呢?我是否遗漏了某些内容,或者是否有理由不应该生成警告?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static int cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int main(int argc, char *argv[])
{
int j;
assert(argc > 1);
qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);
for (j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}
I'm confused with this part:
return strcmp(* (char * const *) p1, * (char * const *) p2);
Why did they do this? Why did they NOT do this: (const char**)
or (const char * const*)
? Don't we get a pointer to a const char if we dereference once for (const char**)
? Dereferencing the second one, don't we get a const pointer that points at a const char. Both of these seem to what strcmp()
asks for: two pointers who point at const chars. What the man page seems to give us const pointers pointing at non-const things, which doesn't seem to be what strcmp()
's declaration is asking for. Even if legal, it doesn't seem like a good idea to give a function something that doesn't fit its parameters. Am I missing something?
Lastly, why does the following not generate at least an error warning:
auto const char * const ptr3 = *(const char **) ptr1; //where ptr1 is
of the form int foo(const void * ptr).
Dereferencing ptr1
once gives us a pointer to a const char, but is not itself const. However, ptr3
is const. So why doesn't the compiler generate a warning? Am I missing something, or is there a reason it shouldn't be generating a warning?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先是最后一个问题:
这很好:
在这里,我可以用 typedef 来简化它:
局部变量中的
const
(用下划线的那个~~~~ ~
) 并不是真正必要的:它指定局部变量ptr3
是const
,而不是它指向的数据是常量。下一个问题:为什么(或为什么不)不
*(const char * const *) ptr1
?那么,
*(const char * const *) ptr1
的类型是const char * const
,如果您使用的是 typedef,则为const string
。但它仅用作右值。 const 右值和非 const 右值没有区别。例如,看下面的代码:显然,
x
和y
得到相同的值。因此,在这里添加 const 并没有真正的语义优势,它只是额外的输入。但是:某些编译器会发出警告...
由于您将指向
const void
的指针转换为指向非 conststring
的指针,某些编译器可能会发出警告,提示您正在丢弃限定符。 C++ 编译器甚至不应该让这样的代码通过,因为它们需要const_cast
从const void *
转换为string *
(又名const char *const *
)。但是:反向转换没问题。将指向非常量对象的指针传递给
strcmp
是可以的。strcmp
采用指向 const 数据的指针这一事实表明strcmp
本身不会修改数据。有很多方法可以编写函数。下面是一些示例。
由于无论如何都要转换变量,编译器会忽略许多不同的潜在错误,但某些编译器可能会发出警告。使用适合您的编码风格的版本。
最后提示:
auto
关键字已过时。现在它实际上没有任何意义——它是默认的存储类说明符。不要使用自动
。Last question first:
This is fine:
Here, I can simplify it with a typedef:
The
const
in the local variable (the one underlined with~~~~~
) is not really necessary: it specifies that the local variableptr3
isconst
, not that the data it points to is const.Next question: Why (or why not) not
*(const char * const *) ptr1
?Well, the type of
*(const char * const *) ptr1
isconst char * const
, orconst string
if you are using the typedef. But it's only used as an rvalue. There is no difference between a const and non-const rvalue. For example, look at the following code:Obviously,
x
andy
get the same value. So there is no real semantic benefit to addingconst
here, it is just extra typing.But: some compilers will give a warning...
Since you are casting a pointer to
const void
to a pointer to non-conststring
, some compilers may give a warning that you are discarding qualifiers. C++ compilers shouldn't even let such code pass, since they'll demand aconst_cast
to convert fromconst void *
tostring *
(a.k.aconst char *const *
).However: the reverse conversion is fine. It is fine to pass pointers to non-const objects to
strcmp
. The fact thatstrcmp
takes pointers to const data indicates thatstrcmp
itself does not modify the data.There are many ways to write the function that are fine. Here are some examples.
Since you are casting variables anyway, the compiler will let a lot of different potential errors slide, but some compilers may give warnings. Use whichever version suits your coding style.
Final tip: The
auto
keyword is obsolete. It doesn't really mean anything these days -- it's the default storage class specifier. Don't useauto
.你问题的第一部分,我认为放置 const 的位置有一定的灵活性,因此 const char ** 和 char * const * 是相同。
问题的第二部分,任何指针都可以分配给 const 指针。反之则会产生错误。您的显式强制转换消除了编译器对指针原始类型的任何了解。
First part of your question, I think there's some flexibility on where you place the
const
, soconst char **
andchar * const *
are the same.Second part of your question, any pointer can be assigned to a
const
pointer. It's going the other way that generates an error. Your explicit cast removed any knowledge the compiler had about the pointer's original type.