Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Void Pointers Question about dereferencing (http://www.programmingforums.org/showthread.php?t=12295)

Soulstorm Jan 2nd, 2007 4:17 AM

Void Pointers Question about dereferencing
 
I have been experimenting with void pointers. I have encountered many problems, since I want to implement them into a very big project, but I made some examples that I believe that if I understand them, I will be able to use them efficiently.

Here is my first example:
:

  1. int main (int argc, char * const argv[]) {
  2.         int *p;
  3.         int a = 100;
  4.         void *v;
  5.         p = &a;
  6.         v = p;
  7.         std::cout << v;
  8.         return 0;
  9. }


The result I am getting is '0xbffff9c0' from the cout function. Actually, I had predicted it, but I don't know how can I access the contents of the void pointer. Can you help?

Another example:

:

  1. void f(void *p){
  2.         printf("%s",p);
  3. }
  4.  
  5. int main (int argc, char * const argv[]) {
  6.         char p[] = "hello!";
  7.         f(p);
  8.         return 0;
  9. }

The above code works as expected. It shows 'hello'. But if I replace the printf fuunction with the cout:
:

  1. void f(void *p){
  2.         cout << p;
  3. }
  4.  
  5. int main (int argc, char * const argv[]) {
  6.         char p[] = "hello!";
  7.         f(p);
  8.         return 0;
  9. }

I get an address! (0xbffff9b8).

Can you please explain to me why this is happenning (in both examples) and what can I do to dereference a void pointer so that I can access the elements it points to?

bl00dninja Jan 2nd, 2007 4:36 AM

the whole 'point' of a void pointer is to point to an object of unknown type at run-time, rather than compile-time. this is usually done with polymorphism (one thingie can be one of many thingies). the simple example can be animal sounds.

you start your program with several classes, all inheriting from the abstract class animal. it has a pure virtual function known as sound, (denoted by function_name() = 0) which has the property of echoing the animal sounds by those which the user has decided upon. we use a switch @ run-time to find out which animal sound we should make!

if this doesn't make sense, read up on c++ and polymorphism.

good luck!

grumpy Jan 2nd, 2007 5:23 AM

Bl00d, this has nothing to do with polymorphism.

Quote:

Originally Posted by Soulstorm (Post 122011)
Here is my first example:
:

  1. int main (int argc, char * const argv[]) {
  2.     int *p;
  3.     int a = 100;
  4.     void *v;
  5.     p = &a;
  6.     v = p;
  7.     std::cout << v;
  8.     return 0;
  9. }

The result I am getting is '0xbffff9c0' from the cout function. Actually, I had predicted it, but I don't know how can I access the contents of the void pointer. Can you help?

First a nitpick: it would help if you got your language straight, both in your description of output streams, and with usage of void pointers. Your description of cout as a function is woefully incorrect: cout is an object. When data is streamed to cout (eg cout << data) that data is written to a standard output device (normally the screen). I pick on this because, unless you can actually describe what streams are or what void pointers are, you have no hope of using them correctly. And using them correctly is a prerequisite to being able to use them (to use your description) "efficiently".

Now, to answer your question.....

C++ output streams (of which cout is one) provide an operator<< which takes a void pointer, and prints the address contained in the pointer to the stream.

It is not possible to "access" the contents of a void pointer directly as, by definition, a void pointer points at nothing in particular (i.e. there are no contents to access). The point (no pun intended) of void pointers is that they can point at anything. If you want to access whatever is being really pointed at, you (the programmer) need to know the type of what is really being pointed at. If you know that the pointer actually points at an int, convert the void pointer into a pointer to int. To get the value of that int, dereference the pointer to int.

In code, in your example, you would do this as;
:

  std::cout << *(static_cast<int *>(v));
The static_cast converts v into a pointer to int. The * out the front dereferences that pointer to int, and extracts the int being pointed at.

One problem with void pointers is that they can be converted to anything. So you could also do this;
:

  std::cout << *(static_cast<float *>(v));
which will attempt to print out the floating point value located at the address stored in v. This will sale past the compiler with no problems (casting a void pointer to any other pointer is allowed, and the compiler trusts you to do a valid conversion) but will print garbage because the value being pointed at is actually an int.

Comment to ponder on as you get more advanced: in practice, printing an int as a float will often yield garbage output. Technically, it is actually undefined behaviour (as that term is defined in the C++ standard), and a program crash is an equally correct outcome.

Quote:

Originally Posted by Soulstorm (Post 122011)
Another example:

:

  1. void f(void *p){
  2.     printf("%s",p);
  3. }
  4.  
  5. int main (int argc, char * const argv[]) {
  6.     char p[] = "hello!";
  7.     f(p);
  8.     return 0;
  9. }

The above code works as expected. It shows 'hello'.

Minor nitpick: Actually, it shows "Hello", not 'Hello'.

The reason is that the "%s" format specifier you have supplied explicitly tells the printf() function that p is actually a C-style string.

Quote:

Originally Posted by Soulstorm (Post 122011)
But if I replace the printf fuunction with the cout:
:

  1. void f(void *p){
  2.     cout << p;
  3. }
  4.  
  5. int main (int argc, char * const argv[]) {
  6.     char p[] = "hello!";
  7.     f(p);
  8.     return 0;
  9. }

I get an address! (0xbffff9b8).

Can you please explain to me why this is happenning (in both examples) and what can I do to dereference a void pointer so that I can access the elements it points to?

The reason is that you haven't told the stream to print a string; you've told it to print out a void pointer, and it is doing exactly that: it is printing the address stored in v.

If you want the stream to print out the string "Hello", you need to convert the void pointer into a pointer to char. When it receives a pointer to char, the stream operators (by convention) treat it as a C-style string (an array of char, with the last one being a char with value zero.

:

void f(void *p){
    cout << static_cast<char *>(p);
}


bl00dninja Jan 2nd, 2007 5:35 AM

yeah, about that...this is one of those posts where you need to calll the number below...i am currently wasted.

Soulstorm Jan 2nd, 2007 5:36 AM

I see. Thanks a lot for clearing all these stuff up for me, grumpy. Also, I knew about cout not being a function, but I had to go afk immediately, and it seems I didn't quite realize what I was typing there. Whatever the case, thanks a lot.

As far as void pointers are concerned, here is the thing I want to do: I want to create a linked list which, apart from the normal data they should contain (a pointer to the next element, and a pointer to the previews one), I want them to hold any kind of data, without having to use templates. Why am I obsessed to do it this way?

Consider it as a learning procedure. I believe that way I can create an interface similar to the Objective C's NSArray, which is an array that can hold any kind of data (ex. in the first slot, you can have an NSSTring and in the second one you can have an NSDictionary). I may not be able to do it (it's just an idea, after all).

Are void pointers the right way to do it?

grumpy Jan 2nd, 2007 6:42 AM

Short answer is no. One of the worst possible ways to learn a new programming language is to try to replicate features from another language. And you're trying to learn C++ by replicating a capability of Objective C which C++ is not really designed to support. Similarly, trying to learn Objective C by replicating something like C++ templates would be a poor way to learn Objective C.

That said, there are ways. But they require moderately advanced knowledge of C++, and some other programming methodologies, which you don't yet have.

ONLY OBSESSIVE FOOLS WILL READ ON!!!!

You're talking about a generic container, with different types of elements able to be placed into one container. Objective C supports that more easily, as all types are derived from a base type (id). In C++, there is no universal base type.

The closest you can come would be an array that works with a specific set of types. If those types are only basic types (int, float, pointers, etc) you can employ a union to hold the data, but you also need some other information (eg an enumerated type) to keep track of what data type is actually stored in the union. If the types you want to store include C++ classes, you could do do some hackery with void pointers, and would still need to carry around information about the type of object being stored. And you would need to recompile every time you want to introduce a new type of object into your container (in effect, because a void pointer must be converted into a pointer to the actual type before the actual object can be used).

You will find doing the above non-trivial, because C++ isn't really intended to be used for such things: one of the premises of C++ is that a function that receives a generic void pointer KNOWS what conversions are needed before that void pointer can be used.

There are some more advanced techniques to do the sort of thing you want (eg a common base class for all types you wish to store in the array; defining such a base class is non-trivial and also gives code maintenance nightmares) or introspection techniques associated with distributed object frameworks (CORBA, DCOM, etc). I would recommend you learn more of the basics of C++ before trying to use such things.

Soulstorm Jan 2nd, 2007 6:54 AM

I didn't try to learn C++ by replicating ObjC's features, or the other way around. It's just a game for me. I know Obj-C very well, believe me. But haven't you ever felt you want to do something just for the sake of doing it?

Anyway, thanks for the advice, and it never hurts asking, so I did. Besides, since I have never been involved with void pointers, it's a good opportunity to do so, even if that's not going to lead into a valid project. I'm 20 years old, I still have time to mess around a little bit. :)

EDIT:
Quote:

Objective C supports that more easily, as all types are derived from a base type (id). In C++, there is no universal base type.
Correct me if I'm wrong, but I believe ObjC classes derive from NSObject, not an object of type id. Some Cocoa classes do not even derive from that. And I don't think that NSArray rely on what you said to hold any type of class. I think it relies on the fact that none of the class the programmer creates is treated internally like C++ treats it's own classes, since all classes are created using pointers. The compiler knows what type of class you created when it sees it's name, but it actually allocates the memory manually (with the inherited -alloc function). So, an NSArray does not contain any object, but just pointers to classes, that have been manually allocated elsewhere. And that's why I believe this pattern can be simulated in C++.

It is simulated anyway into the CoreFoundation Framework by Apple, which, among other things, provides classes that behave like an NSArray.

grumpy Jan 2nd, 2007 9:00 AM

Quote:

Originally Posted by Soulstorm (Post 122018)
Correct me if I'm wrong, but I believe ObjC classes derive from NSObject, not an object of type id. Some Cocoa classes do not even derive from that.

Catch is there are different variants of Objective C, from different vendors. So there are variations in this sort of thing. What you're describing is Apple's take on it (which is admittedly the most common one).
Quote:

Originally Posted by Soulstorm (Post 122018)
And I don't think that NSArray rely on what you said to hold any type of class. I think it relies on the fact that none of the class the programmer creates is treated internally like C++ treats it's own classes, since all classes are created using pointers. The compiler knows what type of class you created when it sees it's name, but it actually allocates the memory manually (with the inherited -alloc function).

The closest equivalent, in C++ would be a programmer being able to make assumptions about how the compiler implements types (eg the layout of bits in an int or float, the layout of classes and structures, etc etc). The catch is that the C++ standard deliberately leaves those things up to the implementer of the C++ compiler. The C++ programmer who relies on particular implementation of types will, invariably, write code that works with a particular compiler, but will not be guaranteed to work with other compilers.
Quote:

Originally Posted by Soulstorm (Post 122018)
So, an NSArray does not contain any object, but just pointers to classes, that have been manually allocated elsewhere. And that's why I believe this pattern can be simulated in C++.

I'm not arguing with you there. In fact an early version of GNU's implementation of Objective C was just a preprocessor that output code which is fed directly to the GNU C compiler. But that sort of implementation relies on specific knowledge of how the C compiler does business.

So, if you wanted, it is definitely feasible to write a Objective C interpreter/compiler or library in C or C++.

What is less feasible is providing equivalent functionality for a C++ programmer which, from your wording, I assumed was what you were about. One characteristic of a C++ compiler is that, at run time, most type information is unavailable. So there is no technique in C++ that allows calling an arbitrary method of an object, given only the name of the method as a string (there are techniques to call specific methods, by use of a map construct, but that relies on entries being explicitly placed in the map before attempting to use it). The core of the difference is that C++ is a statically typed language (meaning that the program cannot directly access, at run time, information about the type of an object or methods it provides) in contrast to Objective C which is dynamically typed (meaning that, given an arbitrary object, information about its type and methods can be queried at run time). Which means that, given an object in an NSArray, it is possible in Objective C to directly access information about the type and methods it supplies. This is not possible, in C++: to simulate such a thing, it is necessary to do lots of extra bookkeeping (of the type information, of information about the methods) and to accept some constraints on ability to do that with some types but not others.

Game_Ender Jan 2nd, 2007 11:23 PM

This is completely possible in a type safe way as long as you know the type of the object you want to get out. Just use Boost.Any, sorry if that is not what is desired here, but with it you can make a type safe generic container. The only problem is Boost.Any can't down cast, so you need the exact type not a base class type, which can be limiting. With Boost.Any there is no need to add fields to a special structure every time you want to use a new type.

(Yeah- I do need more nails for my shiny Boost hammer)

grumpy Jan 3rd, 2007 1:51 AM

Quote:

Originally Posted by Game_Ender (Post 122084)
This is completely possible in a type safe way as long as you know the type of the object you want to get out.

I agree. But Soulstorm's question concerned simulation of a capability of Objective C, which (in rough, handwavy terms) allows this to be done even when you don't know the type of object you want to get out.


All times are GMT -5. The time now is 1:21 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC