【问题标题】:Cast function argument passed by rereference in C在 C 中通过引用传递的强制转换函数参数
【发布时间】:2020-12-25 14:44:12
【问题描述】:

我有以下功能。它适用于short

void foo (short n, short * res)
{
  *res = n*2;
}

我想将结果存储在double 变量中。例如:

short in = 5;
double out = 0;
foo(in,&out);

但是这样的结果是一些垃圾。有没有办法在这种情况下强制转换这些类型,或者唯一的解决方案是使用 short 类型的一些临时变量?

【问题讨论】:

  • 在调用中使用正确类型的变量,然后赋值给最终的目标变量。
  • 关于选角,并不是什么“神奇”的东西就能让事情变得正确。相反,它是一种欺骗、愚弄甚至对编译器撒谎关于某些表达式类型的方法。而且编译器很愚蠢,它会相信你告诉它的东西,即使它不是真的(比如告诉它这个“指向double”的指针应该被视为“指向short”的指针)。
  • 顺便问一下,这个函数返回int,并且总是返回0的目的是什么?如果您实际上没有返回计算值,则该函数应具有返回类型void
  • @Someprogrammerdude 是的,在这个特定的示例中返回这样的int 是没有用的,它是原始函数的剩余部分,已针对问题进行了简化

标签: c floating-point type-conversion integer function-definition


【解决方案1】:

如果你不能改变功能,那么我会这样做:

short in = 5;
short tmp;
double out;
foo(in,&tmp);
out = tmp;

如果您经常这样做,请考虑像 @einpoklum 在他的 answer 中所做的那样编写一个包装器,如下所示:

void foo_wrapper(short n, double *out)
{
    short tmp;
    foo(n, &tmp);
    out = tmp;
}

我想理论上可以通过强制转换来实现,但我建议不要这样做。做错的风险很高,你可能会遇到难以追踪的错误,如果你进行显式转换,编译器不会给你警告。我写了一篇关于this answer@

在这种特殊情况下,请注意函数foo 不知道结果类型。所以你需要一个临时变量。您可以通过使用 out 变量作为它自己的临时变量并进行一些强制转换来摆脱它但我强烈建议不要这样做!

short in = 5;
double out;
foo(in, (short*)&out);
out = *(short*)&out; // Evil! Avoid code like this!
printf("%f\n", out);

这适用于我的机器,但它确实违反了 @chqrlie 在 cmets 中所写的别名规则。不要这样做!

@chqrlie 还编写了一种替代方法,没有额外的变量,也没有恶意转换。它有效,但是啊!也不要这样做:

short in = 5; 
foo(in, &in); // No! Just don't!
out = in;     

当然,如果您需要原始值,它不会起作用,但这很明显。这里的主要缺陷是它非常糟糕。不要为了不同的目的重用变量,只是为了摆脱一个临时变量。

【讨论】:

  • 我猜理论上可以通过强制转换而不是在这种特殊情况下:shortdouble 的编码对于强制转换方法来说太不同了。跨度>
  • @chqrlie 我用邪恶的铸造做了一个解决方案;)
  • 有趣!此解决方案违反了别名规则。它还假设short 没有比double 更严格的对齐要求,这是一个公平的假设,只有在不正常的 DS9K 上才会失败:) 更简单的是:short in = 5; foo(in, &in); out = in;
  • @chqrlie 好方法 :) 不幸的是,并非一直如此,因为在某些情况下需要保持原始数据的安全
  • @chqrlie 你的建议伤害了我的眼睛。 :D 但我更新了答案。不错。
【解决方案2】:

使用强制转换是个坏主意。

对于初学者来说,不清楚为什么要使用浮点类型而不是整数类型,例如 intlong int

如果语句

*res = n*2;

可以为short 类型的对象产生溢出,那么你应该重写这个函数

void foo (short n, int * res)
{
  *res = n * 2;
}

注意表达式n * 2的结果在你原来的函数中已经有int类型了。

如果问题与溢出无关,那为什么不直接写

short res;

foo( n, &res );

double d = res;

或者你需要像这样重写函数

void foo (short n, double * res)
{
  *res = n * 2.0;
}

但在任何情况下都不要使用任何强制转换。

【讨论】:

  • 感谢您的回答,但使用 short 类型函数和带有结果的 double 变量是项目的“工具”,我必须在不改变其类型的情况下使用它们
  • @Ans-lte 正如我在这种情况下所写的,只需将对象 res 分配给 double 类型的对象。
【解决方案3】:

除了@klutt 的有效answer,请记住,如果您多次这样做,通常最好将整个内容包装在一个函数中:

int foo_d (short n, double * result)
{
  short result_inner;
  int retval = foo(n, &result_inner);
  *result = (double) result_inner;
    // Note to @Ans-lte: The explicit cast here isn't necessary,
    // the conversion will happen anyway.
  return retval;
}

【讨论】:

  • 不需要*result = (double) res_inner 中的转换,无论如何该转换都会隐式发生。
  • @Someprogrammerdude:是的,我只是想明确一点。
  • auto retval 在 C 中不是惯用的,并且与它的 C++ 用法具有不同的含义,它将retval 定义为int,而不管初始化程序的类型。将类型显式指定为 int retval 会更容易混淆。
  • 在不需要时进行显式转换是邪恶的。避免这种情况。您完成的唯一一件事就是如果操作不当则隐藏警告,并且它会给出零值。此外,您对 auto 的使用完全不是意识形态的。即使在这种特殊情况下确实有效,也没有充分的理由在 C 中使用该关键字。
  • @klutt:抱歉,已编辑。这是我心中的 C++ 作者 :-(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-11
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多