Sign in to follow this  

problem with Void Pointer

This topic is 3814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I tried to cast from a float pointer to a void pointer and i failed. void* sum(void* x, void* y) { return ((void*)(*((float *)x) + *(float*)y)); } I got compiler error: error C2440: 'type cast' : cannot convert from 'float' to 'void *'.

Share this post


Link to post
Share on other sites
For the love of god, why?

Your error is because you cast the void pointers to float pointers, which you dereference and add together. You then try to cast the resulting float to a void pointer (illegally). Take the address of the result and return that.

You still have problems though. For starters, you will be returning the address of a value on the stack, and that's a no-no.

This should compile:
void* sum(void* x, void* y)
{
return (void*)&(*((float *)x) + *((float*)y));
}

But don't do that. Just pass in floats, and return a float.

Share this post


Link to post
Share on other sites
Oops, you'd probably have to store the result of the addition in a temp variable and take the address of that, instead of what I did.

But here, this will work even better:
float sum(float x, float y)
{
return x + y; //wasn't that quick and painless?
}

edit:
Quote:
Original post by Watchman234
but i dont understand why does it work:
return ((void*)(*(int*)x + *(int*)y));
it works well


No, it doesn't. It certainly doesn't do what you think it does. There you add together x and y as ints, resulting in an int. You then cast the result to a void pointer, which unfortunately works, because an address can be represented as an integer. The pointer will, of course, point at complete garbage, because you're treating the result of an arbitrary addition as a valid location in memory.

In short, don't use void pointers. Ever.

Share this post


Link to post
Share on other sites
but this is not my purpose , my purpose is:
typedef enum { SIZE_OF_INT , SIZE_OF_LONG, SIZE_OF_FLOAT, SIZE_OF_CHAR } SIZE;

void* sum(void* x, void* y, SIZE size)
{
switch(size)
{
case SIZE_OF_INT:
return ((void*)(*(int*)x + *(int*)y));
case SIZE_OF_FLOAT:
return ((void*)(*((float *)x) + *(float*)y));
case SIZE_OF_LONG:
return ((void*)(*(long*)x + *(long*)y));
case SIZE_OF_CHAR:
return ((void*)(*(char*)x + *(char*)y));

}
return NULL;
}

Share this post


Link to post
Share on other sites
The compiler say you can't convert a float to a pointer to a void. First you convert two void pointers to floats ( the *((float *)x) and *(float*)y) does this) and then you add them together, resulting in a float. Then you try and convert your float with the (void *) which isn't allowed (this is what the compiler complains about).
I would avoid something like this, really, since I don't see the point of it at all. You can't send anything but floats to this function and get a useful result anyway so it seems strange.
Something that might fix it would be to throw in an & to convert the resulting float to a float pointer which would be converted to a void pointer. I do suspect that it might lead to some unexpected behavior though with the function creating a temporary variable which then falls out of scope when the function returns, which leaves your returned void pointer pointing to something it shouldn't.

Can't test it at the moment but here's what I mean:

void* sum(void* x, void* y)
{
return ((void*) &(*((float *)x) + *(float*)y));
}



Edit: Beaten to it by miles, I see ;)

However, with your added post, I do realize that the size of float ant int are the same on many modern system ? You would be far better off to make a template.


Share this post


Link to post
Share on other sites
Quote:
Original post by Watchman234
but this is not my purpose , my purpose is:
typedef enum { SIZE_OF_INT , SIZE_OF_LONG, SIZE_OF_FLOAT, SIZE_OF_CHAR } SIZE;

void* sum(void* x, void* y, SIZE size)
{
switch(size)
{
case SIZE_OF_INT:
return ((void*)(*(int*)x + *(int*)y));
case SIZE_OF_FLOAT:
return ((void*)(*((float *)x) + *(float*)y));
case SIZE_OF_LONG:
return ((void*)(*(long*)x + *(long*)y));
case SIZE_OF_CHAR:
return ((void*)(*(char*)x + *(char*)y));

}
return NULL;
}


Welcome to the wonderful world of C++:

template <class T>
T sum( T x, T y )
{
return x + y;
}

Share this post


Link to post
Share on other sites
ints and floats are the same size: 4 bytes

what you are trying to do is the worst thing imaginable. I don't think a situation exists in which this is the correct solution.

-me

Share this post


Link to post
Share on other sites
Quote:
Original post by Watchman234
but i use C and not C++


...Don't?

Why do you have to use C? And if there is a good reason for it, just overload functions for the different types you need. Or, since you appear to be only working with built-in types, just add them together normally?

Share this post


Link to post
Share on other sites
What are your reason to want to do this kind of thing, there must be a good reason and a far better way of doing it ;)

Share this post


Link to post
Share on other sites
Apart from ze goggles, which do nothing, shouldn't you pass the result pointer as argument as well? God only knows where the pointer you're returning will be located.

To me, the original code reads like this (pardon the c++-ish syntax):

void* sum(void* x, void* y)
{
float lx = *( (float*) x );
float ly = *( (float*) y );

float result = lx + ly;
return (void *)(&result);
}




Isn't this returning of address of local stack variable?

My guess would be you'd need something like this:

void sum( void *x, void *y, void *result )
{
float lx = *( (float*) x );
float ly = *( (float*) y );

*result = (lx + ly);
}




With the resulting majick of templates being something like this:

#define TYPEID char

#define TYPE_INT 0
#define TYPE_FLOAT 1
#define TYPE_CHAR 2

#define TYPED_DEREF( TYPE, VARIABLE ) *( (TYPE*) VARIABLE )
#define SUM( TYPE ) ( TYPED_DEREF( TYPE, x ) + TYPED_DEREF( TYPE, y ) )

void sum(void* x, void* y, void *result, TYPEID id)
{
switch(id)
{
case TYPE_INT:
TYPED_DEREF( int, result ) = SUM( int );
break;
case TYPE_FLOAT:
TYPED_DEREF( float, result ) = SUM( float );
break;
case TYPE_CHAR:
TYPED_DEREF( char, result ) = SUM( char );
break;
}
}




And out comes something that is even readable...

Now pardon me while I take a shower. I feel dirty...

[Edited by - Antheus on July 9, 2007 8:00:09 PM]

Share this post


Link to post
Share on other sites
Damn, this is bad even for C.

I'm assuming you want a variant, basically. The way to do this in C is with unions:

typedef union {
char ch;
int i;
unsigned u;
float f;
} variant_data_t;


Probably with type data built in:

typedef enum { VARIANT_CHAR, VARIANT_INT, VARIANT_UNSIGNED, VARIANT_FLOAT } variant_type_t;

typedef struct {
variant_data_t data;
variant_type_t type;
} variant_t;


Then, we can do all sorts of fun stuff:

#include <assert.h>

variant_t sum( variant_t lhs, variant_t rhs ) {
variant_t result;
assert( lhs.type == rhs.type );
result.type = lhs.type;

switch( result.type ) {
case VARIANT_CHAR: result.data.ch = lhs.data.ch + rhs.data.ch; break;
case VARIANT_INT: result.data.i = lhs.data.i + rhs.data.i ; break;
case VARIANT_UNSIGNED: result.data.u = lhs.data.u + rhs.data.u ; break;
case VARIANT_FLOAT: result.data.f = lhs.data.f + rhs.data.f ; break;
default: assert(!"reached");
}

return result;
}

/* Shorthand helper function: */
variant_t variantf( float f ) {
variant_t v = { f, VARIANT_FLOAT };
return v;
}
variant_t varianti( int i ) {
variant_t v = { i, VARIANT_INT };
return v;
}
int variant_toi( variant_t v ) {
switch( v.type ) {
case VARIANT_CHAR: return (int) v.data.ch;
case VARIANT_INT: return (int) v.data.i;
case VARIANT_UNSIGNED: return (int) v.data.u;
case VARIANT_FLOAT: return (int) v.data.f;
default: assert(!"reached");
}
}

int main() {
assert( variant_toi( sum(variantf(12.5f),variantf(12.6f)) ) == 25 );
}





Of course, you really want to use C++, not C, but if you're going to be a masochistic bastard, at least do it right, instead of vying for entry into thedailywtf.com.

Share this post


Link to post
Share on other sites
Quote:
Original post by Watchman234
just a request, before you send the message please try to compile and run it.


Fixed it with edit before you'd even posted this.

Well, except for the use of lhs instead of v inside of variant_tof, but I'm not going to be so insulting to your intelligence as to assume you need every line hand fed to you. The missing .data. everywhere and the misnamed variable use are good exercises for you to practice understanding other people's code, which will far more often be far more broken than mine.

In short: No. [lol]

(Normally I don't even help with C, just on the principle that you shouldn't be using it.)

Share this post


Link to post
Share on other sites
Just use overloaded functions.

float sum(float x, float y){
return x + y;
}

double sum(double x, double y){
return x + y;
}

...

int sum(int x, int y){
return x + y;
}

Share this post


Link to post
Share on other sites
How about this:



#define SUM(x,y) (x + y)

int nResult = SUM(nX, nY);





That should fix all compiler errors :)

EDIT: #define SUM(x,y) (x + y) <- more acurate

[Edited by - rpg_code_master on July 10, 2007 9:57:36 AM]

Share this post


Link to post
Share on other sites
Quote:
use templates?
Exactly, provided the type is known at compile time that is, of coarse since this is C we will have to revert to preprocessor hackery but the result is almost the same.

#define SUM(type) sum_#type

/*************************************/
#define SUM_IMPL(type) \
type sum_#type(type x, type y) \
{ \
return x + y; \
} \
/*************************************/

SUM_IMPL(float)
SUM_IMPL(double)
SUM_IMPL(int)
SUM_IMPL(char)
// ...

#undef SUM_IMPL

// Call as SUM(float)(x, y)




If the type is only known at runtime then as MaulingMonkey said what you want is a discriminated union (aka variant).
Quote:
I have got a run time error.
Then use a debugger to fix it.
Quote:
Why do you have to use C? And if there is a good reason for it, just overload functions for the different types you need. Or, since you appear to be only working with built-in types, just add them together normally?
Quote:
Just use overloaded functions.
Since this misconception seems to be extremely common, C does not allow overloaded functions

Edit:
Quote:

<snip>
That should fix all compiler errors :)


And introduce a million runtime errors from things like SUM(5, 8) * 10

Edit 2: I forgot that the forums preprocessor doesn't play nicely with trailing '\'s in source blocks so had to add trailing spaces in the macro, remove them to compile it.

Share this post


Link to post
Share on other sites

This topic is 3814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this