这个问题是关于使用函数指针的,函数指针并不完全兼容,但是我希望只要我的代码只依赖于兼容的部分,我就可以使用函数指针让我们从一些代码开始了解这个想法:

typedef void (*funcp)(int* val);

static void myFuncA(int* val) {
  *val *= 2;
  return;
}

static int myFuncB(int* val) {
  *val *= 2;
  return *val;
}

int main(void) {
  funcp f = NULL;
  int v = 2;

  f = myFuncA;
  f(&v);
  // now v is 4

  // explicit cast so the compiler will not complain
  f = (funcp)myFuncB;
  f(&v);
  // now v is 8

  return 0;
}

虽然myFuncAmyFuncB的参数相同且完全兼容,但返回值不是,因此只是被调用代码忽略我tried the above code并且它使用GCC工作正常。
到目前为止,我从herehere中了解到的是,根据标准的定义,这些函数是不兼容的,并且可能导致未定义的行为然而,我的直觉告诉我,我的代码示例仍然可以正常工作,因为它在任何方面都不依赖于不兼容的部分(返回值)然而,在对this question的回答中提到了堆栈可能的损坏。
所以我的问题是:我上面的示例是有效的C代码,所以它总是按预期工作(没有任何副作用),还是取决于编译器?
编辑:
我想这样做是为了使用一个带有“les powerful”接口的“更强大”函数。在我的示例中,funcp是一个接口,但我想提供额外的功能,如myFuncB供选择使用。

最佳答案

同意这是不明确的行为,不要这样做!
是的,代码函数,也就是说它不会掉下来,但是返回void后指定的值是未定义的。
在非常旧的“C”版本中,返回类型是未指定的,int和void函数可以“安全地”混合使用在指定的累加器寄存器中返回的整数值我记得用这个“功能”写代码!
对于几乎任何你可能返回的结果都可能是致命的。
再往前看几年,浮点返回值通常使用fp协处理器(我们仍在80年代)寄存器返回,因此不能混合使用in t和float返回类型,因为如果调用方不去掉该值,协处理器的状态将被混淆,或者去掉一个从未放在那里的值并导致fp异常。更糟糕的是,如果您使用fp仿真构建,那么fp值可能会在堆栈上返回,如下所述。同样,在32位构建上,可以传递64位对象(在16位构建上,可以有32位对象),这些对象将使用多个寄存器或堆栈返回。如果它们在堆栈上并且分配了错误的大小,则会发生一些本地跺脚,
现在,c支持结构返回类型和返回值副本优化如果您不正确匹配类型,所有赌注都将被取消。
还有一些函数模型让调用者为调用的参数分配堆栈空间,但是函数本身释放堆栈调用者和实现在参数和返回值的数量或类型上的分歧将是致命的。
默认情况下,C函数名是导出和链接的,只是函数名定义了符号,因此程序的不同模块可能对函数签名有不同的视图,链接时会发生冲突,并可能生成非常有趣的运行时错误。
在c++中,函数名被高度修饰,主要是为了允许重载,同时也有助于避免签名不匹配这有助于保持参数同步,但实际上(正如@Jens所指出的那样),返回类型没有编码到修饰名称中,主要是因为返回类型没有用于重载解析(以前没有,但我认为现在偶尔会影响)。

关于c - 转换具有不同返回类型的函数指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49407747/

10-11 21:55
查看更多