5

I have this piece of code that works in C but not C++, is that any way to make it work on both C and C++ ?

void foo(void* b)
{
   int *c = b;
   printf("%d\n",*c); 

}

int main ()
{
 int a = 1000;

 foo(&a);
 return 0;
}

output:

C++:

1 In function 'void foo(void*)':
2 Line 3: error: invalid conversion from 'void*' to 'int*'
3 compilation terminated due to -Wfatal-errors.

C:

1000

Please help

user1998844
  • 449
  • 8
  • 18
  • 1
    `int *c = static_cast(b);` – Henri Menke Apr 03 '17 at 03:39
  • 1
    You could explicitly cast it from void* to int* but that would be unnecessary in C. – Ajay Brahmakshatriya Apr 03 '17 at 03:39
  • 2
    C and C++ are *different* programming languages. Why do you expect to be able to write the same code working on both? – Basile Starynkevitch Apr 03 '17 at 04:31
  • Note that (even using the cast) this will cause silent undefined behaviour if you pass it a pointer that wasn't originally an `int *` (more or less) – M.M Apr 03 '17 at 04:54
  • You also have a (silent) error in your C code (don't know about C++). Calling a function accepting a variable number of arguments (`printf`) without a prototype in scope invokes **undefined behaviour**. Increase the warning level of your compiler(s) and mind the warnings! – pmg Apr 03 '17 at 08:26

3 Answers3

10

invalid conversion from void* to int*

In order to make an conversion from void* to int* you will need to cast b as int* when assigning it to c. Do:

int *c = (int*) b;

This works in C++ and in C.

BusyProgrammer
  • 2,783
  • 5
  • 18
  • 31
  • Yet necessary for the OP @HenriMenke . He wants C/C++ compatible code. Plus 1 vote. – Santiago Varela Apr 03 '17 at 03:41
  • @HenriMenke Thanks for pointing that out! Will do that, just give me a sec. – BusyProgrammer Apr 03 '17 at 03:42
  • Don't @ABusyProgrammer. The OP specifically said "is that any way to make it work on both C and C++ ?"... – Santiago Varela Apr 03 '17 at 03:43
  • Sorry, @user54264611634646244 got caught up in the rush, I was going to inform Henri about the question. This cast is not the best for C++, but it is compatible with both languages, just as the question asks :) – BusyProgrammer Apr 03 '17 at 03:44
  • @HenriMenke You're right, but for the sake of this question, the cast I used works in bith languages. Its not the best for C++, which I'll update in my answer, but it suits OP's question exactly :) – BusyProgrammer Apr 03 '17 at 03:46
  • @HenriMenke the point is that C++ casts would be wrong for this answer, because it wouldn't compile with C. We're saying the same thing now, but you're deviating from your first point which was wrong. – Santiago Varela Apr 03 '17 at 03:46
  • @Henri Menke: Firstly, the point of the question is to create cross-compilable C/C++ code. No C++-specific features are allowed. Secondly, this cast is inherently unsafe and no C++-style cast can make it safer. – AnT stands with Russia Apr 03 '17 at 03:47
  • The deleted answer by @MarkusL also raises a valid point, *"if you are just going to cast to* `int *` *immediately upon entering the function, why not make that the parameter type as well?"* – David C. Rankin Apr 03 '17 at 03:51
  • 1
    @David C. Rankin: This piece of code is obviously intended to serve as an experiment intended to target this very specific feature: conversion to and from `void *` pointers. – AnT stands with Russia Apr 03 '17 at 03:57
  • I get that point, but the problem remains, unless there is a manner to validate what is passed through `void *b`, is in fact type `int *` it is a crap-shoot at best. The point being, unless it is mandatory to use a void pointer, you are better off allowing the compiler to provide type checking by passing the value as the type desired. – David C. Rankin Apr 03 '17 at 04:02
  • @DavidC.Rankin `void*` is sometimes used as "generic handle", with the intention that the user will know what to do with it; I believe this is more common with C code, but that's just speculation because C++ doesn't like it. The code could be intended to work with a library that does this. – Justin Time - Reinstate Monica Apr 03 '17 at 05:23
4

C allows implicit conversion between void* and any pointer to object type, C++ does not. To make your code compatible with both languages, you could type foo( (void*)&a );.

However, using void pointers is discouraged in both languages - they should only be used as a last resort. If you want the function to be type-generic in C, you'd use the _Generic keyword. In C++ you'd use templates.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

Considering all the casting issues with both the languages, the correct way would be -

#ifdef __cplusplus
#define cast_to_intp(x) static_cast<int*>(x)
#else
#define cast_to_intp(x) (x)
#endif

And then use

int *c = cast_to_intp(b);
Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • The `static_cast` was an obvious typo. About the inherent unsafe cast, that is what is required here. I don't see how one can get around it. We can assume OP knows what he is doing and using the cast appropriately. – Ajay Brahmakshatriya Apr 03 '17 at 04:09
  • @AnT Which part do you think wont compile? – Ajay Brahmakshatriya Apr 03 '17 at 04:10
  • Casts from `void *` to other pointer types are inherently unsafe. And `static_cast` can do nothing to improve the safety of this cast. The above will only pointlessly clutter the code with unnecessary preprocessor branching and macro names. So, what does this achieve then? – AnT stands with Russia Apr 03 '17 at 04:14
  • If the user has made sure that the cast is correct (using some other parameter containing the enum of the type or something similar, not in this case because this is just an experimental setup), the cast would be safe. The behavior of the cast will be completely defined. – Ajay Brahmakshatriya Apr 03 '17 at 04:18
  • My question is: what is the point of your macro then and what does it achieve compared to plain and simple `int *c = (int *) b;`, which works in both languages? (You are still missing `#endif`, BTW). – AnT stands with Russia Apr 03 '17 at 04:26
  • It doesn't silence the warning in case the cast was used on any other type, say an `int`. – Ajay Brahmakshatriya Apr 03 '17 at 04:27
  • Yes, but in the OP's code the cast is used *locally*, to convert a pointer to a pointer. There's no danger of "using it on any other type". Your macro, on the other hand, encourages reuse in other contexts. I.e. your `static_cast` is intended to solve a problem, potential for which you created yourself . (BTW, what is the point of double `((..))` around `x`? Yet in C version a pair of `()` around `x` would be useful). – AnT stands with Russia Apr 03 '17 at 04:31