用于qsort函数指针的Typecast

#include  #include  #include  #include  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 chars的指针。 该手册页似乎为我们提供了指向非const事物的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。 那么编译器为什么不生成警告呢? 我错过了什么,或者是否有理由不应该产生警告?

最后一个问题:

这可以:

 const void *ptr = ...; const char * const ptr3 = *(const char **) ptr1; ^^^^^^^^^^^^ ~~~~~ ^^^^^^^^^^^^ | | +----------------------------+ 

在这里,我可以使用typedef简化它:

 typedef const char * string; const void *ptr = ...; const string ptr3 = *(string *) ptr; ~~~~~ ^^^^^^ ^^^^^^ | | +----------------+ 

局部变量中的const (用~~~~~加下划线的那个)并不是必需的:它指定局部变量 ptr3const ,而不是它指向的数据是const。

下一个问题:为什么(或为什么不)不*(const char * const *) ptr1

好吧, *(const char * const *) ptr1const char * const ,如果使用typedef,则为const string 。 但它只用作右值。 const和非const rvalue之间没有区别。 例如,查看以下代码:

 void *ptr = ...; int x = *(const int *) ptr; int y = *(int *) ptr; 

显然, xy得到相同的值。 所以在这里添加const没有真正的语义好处,它只是额外的输入。

但是:一些编译器会发出警告……

 const void *ptr = ...; string ptr2 = *(string *) ptr; 

由于您将指向const void的指针转换为指向非const string的指针,因此某些编译器可能会发出警告,表明您正在丢弃限定符。 C ++编译器甚至不应该让这些代码通过,因为它们要求const_castconst void *转换为string * (又名const char *const * )。

但是:反向转换很好。 可以将指向非const对象的指针传递给strcmpstrcmp指向const数据的事实表明strcmp本身不会修改数据。

有很多方法可以编写很好的函数。 这里有些例子。

 return strcmp(*(char **) p1, *(char **) p2); return strcmp(*(const char **) p1, *(const char **) p2); return strcmp(*(char * const *) p1, *(char * const *) p2); return strcmp(*(const char * const *) p1, *(const char * const *) p2); // The following are not technically portable, but are portable in practice return strcmp(*(void **) p1, *(void **) p2); return strcmp(*(const void **) p1, *(const void **) p2); return strcmp(*(void * const *) p1, *(void * const *) p2); return strcmp(*(const void * const *) p1, *(const void * const *) p2); 

既然你正在构建变量,编译器会让很多不同的潜在错误滑动,但是一些编译器可能会发出警告。 使用适合您编码风格的版本。

最后提示: auto关键字已过时。 这些日子并没有什么意义 – 它是默认的存储类说明符。 不要使用auto

你的问题的第一部分,我认为你放置const地方有一些灵活性,所以const char **char * const *都是一样的。

问题的第二部分,任何指针都可以分配给const指针。 它会以另一种方式产生错误。 您的显式转换删除了编译器有关指针原始类型的任何知识。