void* 指针算法,不能交换浮点值

问题描述 投票:0回答:2

最近,我很好奇

qsort()
如何在不传递特定类型的情况下进行排序,因此我试图在不知道/关心它的类型的情况下反转数组。

有人告诉我,如果将

void *
转换为
char *
,就可以进行指针运算。

void swap(void *a, void *b)
{
    char tmp = *(char *)a;
    *(char *)a = *(char *)b;
    *(char *)b = tmp;
}

功能

swap()
适用于类型
int
char
但不适用于
float
double
.

我不知道为什么会这样,但我看到了与

memcpy()
交换的实现,因此,我实现了:

void __swap(void *a, void *b, size_t size)
{
    char buf[size];
    memcpy(buf, a, size);
    memcpy(a, b, size);
    memcpy(b, buf, size);
}

使用

swap()
的反向函数实现:

void arr_reverse(void *arr, size_t size, size_t len)
{
    for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
        swap(arr + (i * size), arr + (j * size));
}

使用

__swap()
的反向函数实现:

void arr_reverse(void *arr, size_t size, size_t len)
{
    for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
        __swap(arr + (i * size), arr + (j * size), size);
}

__swap()
效果很好,但我不知道为什么会这样,所以问题是
swap()
__swap()
有什么区别?

我假设这与字体大小有关

c pointers void-pointers pointer-arithmetic
2个回答
2
投票

swap
的实现交换一个字节。
这对字符很好。
对于小整数,这可能 look 很好,但是一旦您的整数大于 255,您也会看到它失败。

注意

__swap
如何有第三个参数,
size
。 当你交换两个项目时,你需要知道三个条信息:

  • 第一项在哪里,
  • 第二项在哪里,
  • 这两个项目的大小是多少。

所以,泛型函数可能不知道确切的类型,但它仍然需要知道该类型的大小(以字节为单位)。


2
投票
  1. void *
    算术是未定义的行为。它是 GCC 扩展,C 标准不允许。

  2. __swap
    swap
    正在做完全不同的事情。第一个是交换
    chunks
    len 的整个
    size
    内存。后者只交换第一个字符,其余字符保持不变,用于更长的类型(如双精度或浮点数)

void swap(void *a, void *b)
{
    char tmp = *(char *)a;
    *(char *)a = *(char *)b;
    *(char *)b = tmp;
}


void __swap(void *a, void *b, size_t size)
{
    char buf[size];
    memcpy(buf, a, size);
    memcpy(a, b, size);
    memcpy(b, buf, size);
}


void invalid_arr_reverse(void *vp, size_t size, size_t len)
{
    unsigned char *arr = vp;
    for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
        swap(arr + (i * size), arr + (j * size));
}


void arr_reverse(void *vp, size_t size, size_t len)
{
    unsigned char *arr = vp;
    for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
        __swap(arr + (i * size), arr + (j * size), size);
}

void printarr(uint32_t *arr, size_t size )
{
    while(size--) printf("0x%08x\n" ,(unsigned)*arr++);
}


int main(void)
{
    uint32_t arr[4] = {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
    uint32_t arr1[4] = {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};

    invalid_arr_reverse(arr, 4, 4);
    printarr(arr, 4);
    arr_reverse(arr1, 4, 4);
    printarr(arr1, 4);
}

https://godbolt.org/z/z1sYrPj6G

字节交换函数必须以不同的方式编写:

void arr_reverse(void *vp, size_t size, size_t len)
{
    unsigned char *arr = vp;
    for (size_t i = 0; i < len / 2; i++)
        for(size_t j = 0; j < size; j++)
            swap(arr + (i * size) + j, arr + (len - i -1) * size + j);
}
© www.soinside.com 2019 - 2024. All rights reserved.