|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Hello,
I'm using some functions to store and retrieve data as a void*. They happen to be an AVL-tree implementation, but that's irrelevant for my question, so let's just think of a black box that handles void*. I think there is no problem as long as I use pointers to data allocated elsewhere, because the standard says that a pointer to whatever, converted to a void*, and converted back to the same whatever, gives the same pointer. But I want to use that code to store small integers (maybe not more than a thousand, but I don't want to hardcode a limit), and I'm wondering whtat is the best portable way to do it. I guess the most natural way to use these functions would be to malloc space for a single int, and use the returned pointer as a void* (with implicit conversion when calling the storing function). Something like that : /* storage */ int *i = malloc(sizeof *i); *i = value_to_be_stored; store_data_as_void_ptr(i); /* retrieval */ int *i = get_data_returned_as_void_ptr(); /* use *i */ However this does not look very efficient in terms of memory, because of the malloc() overhead for every integer, plus the memory used for the void* in the blackbox. I thought that because void* is basically a pointer, and therefore a numeric value, it might be possible to store the value directly into the pointer value. I guess something like the following would work on some architectures : /* storage */ int i = value_to_be_stored; void *data = (void *)i; store_data_as_void_ptr(data); /* retrieval */ int i; void *data = get_data_returned_as_void_ptr(); i = (int)data; /* use i */ However I'm not sure any standard guarantees this to work, so I was looking for a more portable solution. I thought doing some pointer arithmetics : /* global variable to be used for base of pointers */ char base; /* storage */ int i = value_to_be_stored; char *data = &base + i; store_data_as_voir_ptr(data); /* retrieval */ int i; char *data = get_data_returned_as_void_ptr(); i = data - &base; /* use i */ But is this really portable (assuming i is small enough so there is no overflow) ? I guess the pointers will probably be invalid, but as they are never dereferenced, it is alright, isn't it ? Have I made a mistake in all this ? Is there a better way to handle my problem ? Thanks in advanced for your ideas. Natacha |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Hi there,
how about using a union and a type variable, instead of just a pointer? Hope this s Seb ------------------- #include <stdio.h> #include <stdlib.h> #define VALUE_TYPE_POINTER (1) #define VALUE_TYPE_FLOAT (2) #define VALUE_TYPE_INT (3) typedef int value_type_t; typedef struct node_t { value_type_t type; union { int intValue; float floatValue; void* pointerValue; } value; } node_t; node_t* node_new_with_pointer( void* value ) { node_t* result = calloc( 1, sizeof( node_t ) ); result->type = VALUE_TYPE_POINTER; result->value.pointerValue=value; return result; } node_t* node_new_with_int( int value ) { node_t* result = calloc( 1, sizeof( node_t ) ); result->type = VALUE_TYPE_INT; result->value.intValue=value; return result; } int main() { node_t* node = node_new_with_int( 17 ); printf( "node is an int type: %s\nValue: %i\n", node->type == VALUE_TYPE_INT ? "true" : "false", node->value.intValue ); free(node ); char* test="blahblah"; node=node_new_with_pointer( test ); printf( "node is a pointer-type: %s\n" "Pointer is equal to test: %s\n", node->type == VALUE_TYPE_POINTER ? "true" : "false", test == node->value.pointerValue ? "true" : "false" ); free( node ); return 0; } |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
lithiumcat@gmail.com writes:
> I'm using some functions to store and retrieve data as a void*. <snip> > But I want to use that code to store small integers (maybe not more > than a thousand, but I don't want to hardcode a limit) <snip cast void * to int method> > However I'm not sure any standard guarantees this to work, No, you are right. It is not guaranteed to work. It will work in lots of cases, but it is not portable. > so I was > looking for a more portable solution. I thought doing some pointer > arithmetics : > /* global variable to be used for base of pointers */ > char base; > /* storage */ > int i = value_to_be_stored; > char *data = &base + i; > store_data_as_voir_ptr(data); > /* retrieval */ > int i; > char *data = get_data_returned_as_void_ptr(); > i = data - &base; > /* use i */ > > But is this really portable (assuming i is small enough so there is no > overflow) ? I guess the pointers will probably be invalid, but as they > are never dereferenced, it is alright, isn't it ? Clever but, no, not portable. Even constructing an address outside of and object (except for the off-by-one-at-the-end permission) is undefined. The only portable solution that I can think of is the union idea already posted. This, of course, requires changes to the AVL tree code, so it may not be an option. -- Ben. |
|
![]() |
| Outils de la discussion | |
|
|