qecort函数指针的typecast [英] Typecast for qsort function pointer

查看:214
本文介绍了qecort函数指针的typecast的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include< stdio.h> 
#include< stdlib.h>
#include< string.h>
#include< assert.h>

static int cmpstringp(const void * p1,const void * p2)
{
/ *这个函数的实际参数是指向
的指针指向char ,但strcmp(3)参数是指针
到char,因此下面的cast加引用* /

return strcmp(*(char * const *)p1,* * 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指针指向一个const char。这两个似乎都是 strcmp()要求:两个指向const chars的指针。什么man页面似乎给我们指向非常量的const指针,这似乎不是 strcmp()的声明是要求。即使是合法的,给一个函数不适合它的参数似乎不是一个好主意。我缺少什么?



最后,为什么以下内容不会至少生成错误警告:

  auto const char * const ptr3 = *(const char **)ptr1; //其中ptr1是
,形式为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 指定本地变量 ptr3 const ,而不是它指向的数据是下一个问题:为什么(或为什么不)不 *(const char * const *)ptr1

/ code>?



好吧, *(const char * const *)ptr1 的类型 const char * const const string 但它只是用作右值。常量和非常量之间没有区别。例如,查看下面的代码:

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

显然, x y 得到相同的值。因此,在这里添加 const 没有真正的语义上的好处。



一些编译器会给出警告...

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

因为你正在转换一个指针 const void 指向非const string 的指针,一些编译器可能会提示您要舍弃限定符。 C ++编译器不应该让这样的代码通过,因为他们需要 const_cast const void * string * (aka const char * const * )。



但是:反向转换是正常的。将非const对象的指针传递给 strcmp 是很好的。事实上, strcmp 需要指向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);

//以下是技术上不可移植的,但在实践中是可移植的
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


    #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?

解决方案

Last question first:

This is fine:

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

Here, I can simplify it with a typedef:

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

The const in the local variable (the one underlined with ~~~~~) is not really necessary: it specifies that the local variable ptr3 is const, 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 is const char * const, or const 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:

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

Obviously, x and y get the same value. So there is no real semantic benefit to adding const here, it is just extra typing.

But: some compilers will give a warning...

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

Since you are casting a pointer to const void to a pointer to non-const string, some compilers may give a warning that you are discarding qualifiers. C++ compilers shouldn't even let such code pass, since they'll demand a const_cast to convert from const void * to string * (a.k.a const char *const *).

However: the reverse conversion is fine. It is fine to pass pointers to non-const objects to strcmp. The fact that strcmp takes pointers to const data indicates that strcmp itself does not modify the data.

There are many ways to write the function that are fine. Here are some examples.

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);

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 use auto.

这篇关于qecort函数指针的typecast的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆