C 如何通过两个void指针参数交换两个未知确切类型的数字?

C 如何通过两个void指针参数交换两个未知确切类型的数字?,c,C,我需要编写一个函数来替换2个未知类型的“数字” 我不知道确切的类型,我只能使用2个参数 这就是我尝试过的: void swap(void *p1, void *p2) { char p; char * q1 = (char *)p1; char * q2 = (char *)p2; for (int i = 0; i < sizeof(long double); i++) { p = q1[i]; q1[i] = q2

我需要编写一个函数来替换2个未知类型的“数字”

我不知道确切的类型,我只能使用2个参数

这就是我尝试过的:

void swap(void *p1, void *p2)
{
    char p;
    char * q1 = (char *)p1;
    char * q2 = (char *)p2;
    for (int i = 0; i < sizeof(long double); i++)
    {
        p = q1[i];
        q1[i] = q2[i];
        q2[i] = p;
    }
}
这很好,但我的问题是,如果我的
数字
大于
长双精度
(或者没有人…)

我的解决方案行吗?

您的程序应该尝试检索其参数的
sizeof
,以了解要交换多少字节(可能作为第三个参数),否则无法判断参数有多大。使用当前函数,您将覆盖内存,这将导致糟糕的结果-尤其是在更大的程序中。例如,考虑下面的程序。

#include <stdio.h>
int main() {
    int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
    swap(&a[0], &a[4]);
    for (int i = 0; i < 8; i++) {
        printf("%d\n", a[i]);
    }
}

您的程序应该尝试检索其参数的
sizeof
,以了解要交换的字节数(可能是第三个参数),否则无法判断参数有多大。使用当前函数,您将覆盖内存,这将导致糟糕的结果-尤其是在更大的程序中。例如,考虑下面的程序。

#include <stdio.h>
int main() {
    int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
    swap(&a[0], &a[4]);
    for (int i = 0; i < 8; i++) {
        printf("%d\n", a[i]);
    }
}
这很好,但我的问题是,如果我的数字更大(?)
我的解决方案行吗

除非代码知道确切的大小,否则它会有问题。所以,不,OP的解决方案不好。
不知何故,
void swap()
需要知道要交换的数据的大小

我只能使用2个参数

从C99开始,代码可以欺骗并将所有数据作为复合文字放入1参数中

typedef struct {
  void *a;
  void *b;
  size_t sz;
} swap_T;

// Only 1 parameter!!
void swap(swap_T sw) {
  unsigned char * q1 = sw.a;
  unsigned char * q2 = sw.b;
  while (sw.sz > 0) {
    sw.sz--;
    unsigned char p = q1[sw.sz];
    q1[sw.sz] = q2[sw.sz];
    q2[sw.sz] = p;
  }
}

int main(void) {
  double a = 100123000000.2;
  double b = 100065450000.3;
  printf("a: %g, b: %g\n", a, b);
  swap(((swap_T ) { &a, &b, sizeof a } ));  // Compound literal
  printf("a: %g, b: %g\n", a, b);
  return 0;
}
输出

a: 1.00123e+11, b: 1.00065e+11
a: 1.00065e+11, b: 1.00123e+11
代码可以将交换(((swap_T){&a,&b,sizeof a}))封装在一个宏中,该宏看起来像是一个2的函数调用

#define SWAP(a,b) (swap(((swap_T ) { &(a), &(b), sizeof (a) } )))
...
SWAP(a,b);
只要
a
不是一个具有可变逻辑数组(VLA)和副作用的表达式,宏就可以正常工作

当然,如果
a、b
是同一类型,则最好是这样

这很好,但我的问题是,如果我的数字更大(?)
我的解决方案行吗

除非代码知道确切的大小,否则它会有问题。所以,不,OP的解决方案不好。
不知何故,
void swap()
需要知道要交换的数据的大小

我只能使用2个参数

从C99开始,代码可以欺骗并将所有数据作为复合文字放入1参数中

typedef struct {
  void *a;
  void *b;
  size_t sz;
} swap_T;

// Only 1 parameter!!
void swap(swap_T sw) {
  unsigned char * q1 = sw.a;
  unsigned char * q2 = sw.b;
  while (sw.sz > 0) {
    sw.sz--;
    unsigned char p = q1[sw.sz];
    q1[sw.sz] = q2[sw.sz];
    q2[sw.sz] = p;
  }
}

int main(void) {
  double a = 100123000000.2;
  double b = 100065450000.3;
  printf("a: %g, b: %g\n", a, b);
  swap(((swap_T ) { &a, &b, sizeof a } ));  // Compound literal
  printf("a: %g, b: %g\n", a, b);
  return 0;
}
输出

a: 1.00123e+11, b: 1.00065e+11
a: 1.00065e+11, b: 1.00123e+11
代码可以将交换(((swap_T){&a,&b,sizeof a}))封装在一个宏中,该宏看起来像是一个2的函数调用

#define SWAP(a,b) (swap(((swap_T ) { &(a), &(b), sizeof (a) } )))
...
SWAP(a,b);
只要
a
不是一个具有可变逻辑数组(VLA)和副作用的表达式,宏就可以正常工作


当然,如果
a,b
是同一类型的话,那就最好了。

如果它小一些呢?这完全是运气使然。尝试一个更复杂的程序。如果不将输入的大小作为第三个参数传递(例如,使用
qsort
),则没有什么好方法可以做到这一点。否则你只是猜测,这肯定会在某个时候造成混乱。如果你想作弊,你可以创建一个全局函数来存储函数中的大小和引用,但这是一个糟糕的方法。这是家庭作业。那么,不要解释实际任务,而是逐字重复它。当然,要准备好回答无法给出解决方案的问题,并且要有充分的理由。如果解决方案较小,那该怎么办?这完全是靠运气。尝试一个更复杂的程序。如果不将输入的大小作为第三个参数传递(例如,使用
qsort
),则没有什么好方法可以做到这一点。否则你只是猜测,这肯定会在某个时候造成混乱。如果你想作弊,你可以创建一个全局函数来存储函数中的大小和引用,但这是一个糟糕的方法。这是家庭作业。那么,不要解释实际任务,而是逐字重复它。当然,也要准备好回答无法给出解决方案的问题,并提供充分的理由。我不能使用第三个参数。不过,这并不是问题的答案。此外,
sizeof
是一个编译时运算符,在确定运行时传递给函数的指针类型时可能没有用处。@leedianelcrocker Re:“尺寸。。。无法确定传递的指针类型。要交换,指针的类型并不重要。对象的大小很重要,可以通过
sizeof
找到。否则,不清楚您的问题。
sizeof(p)
在使用void指针参数p的函数中,会给出指针的大小。如果尝试sizeof(*p),则会给出一个错误。除非在编译时提交,否则无法获得指向的对象的大小。(或者按照建议使用C11(泛型)。我不能使用第三个参数。不过,这不是问题的答案。此外,
sizeof
是一个编译时运算符,对于确定在运行时传递给函数的指针类型可能没有帮助。@leedinelcrocker Re:“sizeof…”。。。无法确定传递的指针类型。要交换,指针的类型并不重要。对象的大小很重要,可以通过
sizeof
找到。否则,不清楚您的问题。
sizeof(p)
在采用void指针参数p的函数中,将给出指针的大小。如果尝试sizeof(*p),则会给出错误。除非在编译时提交,否则无法获得指向的对象的大小。(或者按照建议使用C11(泛型)。有趣的是,
swap()
函数修改传递的
struct
size\t sz;
成员,这当然不会影响传递内容的来源。有趣的是,您的
swap()
函数修改传递的
struct
size\t sz;
成员,这当然不会影响传递内容的来源。