1

I have the following function. It works with short:

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

I want to store the result in double variable. For example:

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

But in that way the result is some garbage. Is there a way to cast these types in such situation, or the only solution is to use some temp variable of type short?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
ans
  • 378
  • 1
  • 5
  • 18
  • 1
    Use a variable of the correct type in the call, and then assign to the final destination variable. – Some programmer dude Sep 07 '20 at 07:34
  • 2
    Regarding casting, it's not some "magical" thing that will make things right. Rather it's a way to trick, fool and even *lie* to the compiler about the type of some expression. And the compiler is stupid, it will believe what you tell it, even when it's not true (like when telling it that this "pointer to `double`" should be treated as "pointer to `short`"). – Some programmer dude Sep 07 '20 at 07:37
  • By the way, what is the purpose of the function returning an `int`, and always returning `0`? If you don't actually *return* the calculated value, then the function should have the return type `void`. – Some programmer dude Sep 07 '20 at 07:58
  • @Someprogrammerdude yes, in this particular example returning such `int` is of no use, it's a leftover of the original function, that was simplified for the question – ans Sep 07 '20 at 08:11

3 Answers3

5

If you cannot change the function, then I would do something like this:

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

If you do this a lot, consider writing a wrapper as @einpoklum did in his answer like this:

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

I guess it could theoretically be possible with casting, but I would advice against it. The risks of doing it wrong is high, and you might get hard chased bugs, and if you do explicit casts, the compiler will not give you warnings. I wrote a rant about casting in this answer

In this particular case, note that the function foo have no idea of the resulting type. So you will need a temporary variable. You could get rid of that by using the out variable as it's own temporary variable with some casting but I strongly advice against it!

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

This works on my machine, but it does violate aliasing rules as @chqrlie wrote in comments. Do NOT do like this!

@chqrlie also wrote an alternative approach with no extra variable and no evil casting. It works, but UGH! Don't do like this either:

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

Of course it will not work if you need the original value, but that's pretty obvious. The major flaw here is that it's just plain bad. Don't reuse variables for different purposes just to get rid of a temporary variable.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • *I guess it could theoretically be possible with casting* not in this particular case: th encoding of `short` and `double` are too different for a casting approach. – chqrlie Sep 07 '20 at 07:50
  • @chqrlie I did a solution with evil casting ;) – klutt Sep 07 '20 at 08:01
  • interesting! this solution violates the aliasing rules. It also assumes that `short` does not have stricter alignment requirements than `double`, which is a fair assumption only defeated on a perverse DS9K :) a simpler one is this: `short in = 5; foo(in, &in); out = in;` – chqrlie Sep 07 '20 at 08:08
  • @chqrlie nice way :) unfortunately, not all the time, as in some cases it is needed to keep original data safe – ans Sep 07 '20 at 08:20
  • @chqrlie Your suggestion hurt my eyes. :D But I updated the answer. Good one. – klutt Sep 07 '20 at 08:22
1

In addition to @klutt's valid answer, remember that if you do on many occasions, it's usually a good idea to wrap the whole thing in a function:

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;
}
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • The cast in `*result = (double) res_inner` isn't needed, that conversion will happen implicitly anyway. – Some programmer dude Sep 07 '20 at 07:43
  • 1
    @Someprogrammerdude: Yes, I just wanted to be explicit. – einpoklum Sep 07 '20 at 07:44
  • 1
    `auto retval` is not idiomatic in C and has a different meaning from its C++ usage, it defines `retval` as `int` regardless of the type of the initializer. it is much less confusing to specify the type explicitly as `int retval`. – chqrlie Sep 07 '20 at 07:54
  • Explicit casts when not needed is evil. Avoid that. The only thing you accomplish is to hide warnings if not done right, and it gives zero value. Also, your use of auto is COMPLETELY non-ideomatic. There's never a good reason to use that keyword in C, even if it does work in this particular case. – klutt Sep 07 '20 at 08:22
  • @klutt: Sorry, edited. It's the C++ author in me :-( – einpoklum Sep 07 '20 at 08:30
  • I assumed that. You can also rewrite it so that it does not return anything. The original question is edited, and the return value was not relevant to the question. – klutt Sep 07 '20 at 08:35
  • On top of that, a variable is incorrectly spelled, so this would not compile. – klutt Sep 07 '20 at 08:36
  • And that explicit cast... If you change it to the incorrect cast `(char) res_inner`, then you will get wrong results for `foo_d(200, &out)` – klutt Sep 07 '20 at 08:38
1

Using casting is a bad idea.

For starters it is unclear why you want to use a float type instead of an integer type as for example int or long int.

If the statement

*res = n*2;

can produce an overflow for an object of the type short then you should rewrite the function like

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

Pay attention to that the result of the expression n * 2 already has the type int in your original function.

If the problem is not related to the overflow then why not just to write

short res;

foo( n, &res );

double d = res;

Or again you need to rewrite the function like

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

But in any case do not use any casting.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thank you for your answer, but working with `short` types function and `double` variable with result are "tools" of the project which I have to use with no changes of their types – ans Sep 07 '20 at 10:13
  • @Ans-lte As I wrote in this case just assign the object res to an object of the type double. – Vlad from Moscow Sep 07 '20 at 10:17