error: cannot convert 'double*' to 'char*' for argument '1' to 'void swap(char*, char*, unsigned int)'

前端 未结 3 347
悲&欢浪女
悲&欢浪女 2021-01-29 00:14
#include 

void swap( char* pA,  char* pB, unsigned tam) {
    for( unsigned i = 0; i < tam; i++) {
        char tmp = *pA;
        *pA = *pB;
                 


        
3条回答
  •  鱼传尺愫
    2021-01-29 00:43

    There are a number of ways of writing a generic swap function. If it will be used for only one type (so it doesn't need to be generic), the size argument is not needed and you can pass pointers of the relevant type (double * in the question) and swap using indirection.

    extern void double_swap(double *d1, double *d2);
    
    void double_swap(double *d1, double *d2)
    {
        double d = *d1;
        *d1 = *d2;
        *d2 = d;
    }
    

    There might well be advantages to making that into:

    static inline void double_swap(double *d1, double *d2)
    {
        double d = *d1;
        *d1 = *d2;
        *d2 = d;
    }
    

    This could be placed in a header and used safely.

    If it will be used for multiple types, you should use void * in the function arguments (and size_t for the size of the type).

    /*
    ** This declaration belongs in a header if there is more than one
    ** source file that uses it.  If there is only one file, then it
    ** should be declared and defined as a static function.  If the
    ** header doesn't include any other headers that define size_t,
    ** it should #include  as that's the smallest header
    ** that does define size_t.  You could make the function static
    ** inline instead of extern, even if it is in a header.
    */
    extern void generic_swap(void *v1, void *v2, size_t size);
    
    /* Implementation 1: Using VLA */
    void generic_swap(void *v1, void *v2, size_t size)
    {
        char sp[size];
        memmove(sp, v1, size);
        memmove(v1, v2, size);
        memmove(v2, sp, size);
    }
    

    You can use memcpy() if you don't mind living dangerously (you should probably add restrict to the v1 and v2 pointer types if you do that). Again, the function could probably be made static inline to good effect — that also applies to the other implementations below.

    If you don't like the idea of large objects being allocated on the stack, you can copy the data in chunks, but you have to work quite a bit harder.

    enum { CHUNK_SIZE = 64 };
    
    static inline size_t min_size(size_t x, size_t y) { return (x < y) ? x : y; }
    
    /* Implementation 2: Using a fixed size buffer */
    void generic_swap(void *v1, void *v2, size_t size)
    {
        unsigned char sp[CHUNK_SIZE];
        unsigned char *p1 = v1;
        unsigned char *p2 = v2;
        size_t chunk;
        while ((chunk = min_size(size, CHUNK_SIZE)) != 0)
        {
            memmove(sp, p1, chunk);
            memmove(p1, p2, chunk);
            memmove(p2, sp, chunk);
            p1 += chunk;
            p2 += chunk;
            size -= chunk;
        }
    }
    

    Notwithstanding anything that GCC permits, the C standard says you can't increment a void * because there is no known size to increment it by. That's why the pointers are converted to unsigned char *. Clearly, you can tune the chunk size to suit your system. Any power of 2 in the range 16..1024 is probably usable, and other values than a power of 2 can be used if you prefer.

    If you don't mind the overhead, you can dynamically allocate a buffer:

    /* Implentation 3: Using dynamic memory allocation */
    void generic_swap(void *v1, void *v2, size_t size)
    {
        char *sp = malloc(size);
        if (sp != 0)
        {
            memmove(sp, v1, size);
            memmove(v1, v2, size);
            memmove(v2, sp, size);
            free(sp);
        }
    }
    

    If memory allocation fails, the swap doesn't occur. That's bad, so you might fall back on the 'fixed size buffer and swap in chunks', but that is probably quicker than this anyway.

    I would use Implementation 2 in preference to Implementation 3; dynamic memory allocation is expensive. I would probably use Implementation 2 in preference to Implementation 1 as the extra cost of the looping is minimal and using a fixed amount of stack works well. I have not benchmarked any of these to verify my assertions. (If you're swapping megabyte sized lumps of data, you should probably think again — use pointers instead. If you're only swapping smaller chunks, Implementation 1 is simple and safe.)

    With any of the generic swap implementations, your main program becomes:

    int main(void)
    {
        double a = 1.0;
        double b = 2.0;
    
        printf("linea: %d - antes   a(%f) b(%f)\n", __LINE__, a, b);
        generic_swap(&a, &b, sizeof(double));
        printf("linea: %d - despues a(%f) b(%f)\n", __LINE__, a, b);
        return 0;
    }
    

    I'm assuming that at least the declaration of generic_swap() is available before the start of main().

    Note that using either double_swap() or generic_swap() means that no casts are necessary in the code. Minimizing casts is A Good Idea™.

    See also Universal array element swap in C.

提交回复
热议问题