Thread: What is function(void *arg)

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    8

    Exclamation What is function(void *arg)

    What is the (void *arg)? How does it work, and how would I access the data of a void type?

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    it is just a general pointer passing to the function, your function should know what is the actual type of the pointer - and cast it apropriatly before accessing the data.

    It is mostly used in the Callbacks, when library is provided with CB address and some context address.
    Library does not need to know the type of the data - so the pointer is stored as void* and supplied to the CB, when it is called from the library code

    the CB - which is part of the application code - knows exactly what is the data type passed as a context and could cast the pointer accordingly
    Last edited by vart; 03-17-2009 at 12:23 PM.
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    Mar 2009
    Posts
    8
    Thanks, I understand know.

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    This technique isn't used as often in C++ as it is in C, but there are certain situations where it's unavoidable. A typical usage is with callback functions. Lets say you have a shape-drawing library. You want to allow the user to decide what to do when a pixel needs to be drawn. You have no idea what data structures the client code requires to accomplish that so you simply have them pass a pointer to their data. Here's a somewhat contrived example:

    Code:
    // library code
    
    typedef void ( * callback )( int, int, void* ); 
    
    void draw_some_shape( rectangle* bounds, callback function, void* data )
    {
        for( int r = bounds->top; r < bounds->bottom; ++r )
            for( int c = bounds->left; c < bounds->right; ++c )
                if( inside( r, c ) )
                    callback( r, c, data );
    }    
    
    // client code
    
    struct image_data
    {
        int image[ HEIGHT ][ WIDTH ], color;
    };
    
    void draw_pixel( int row, int column, void* data )
    {
        image_data* image = ( image_data* )data;
        image_data->image[ row ][ column ] = image_data->color;    
    }
    
    int main( void )
    {
        image_data data;
        data.color = hsv( 0.333, 0.5, 0.5 );
        rectangle bounds;
        bounds.top = HEIGHT / 2;
        bounds.left = WIDTH / 2;    
        bounds.bottom = HEIGHT;
        bounds.right = WIDTH;
        draw_some_shape( &bounds, draw_pixel, &data );
        // do something useful with the image
        return 0;
    }
    Last edited by Sebastiani; 03-17-2009 at 12:41 PM. Reason: corrections
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sebastiani
    You have no idea what data structures the client code requires to accomplish that so you simply have them pass a pointer to their data.
    That said, this is one situation where it is avoidable in C++ by means of C++ templates, e.g.,
    Code:
    // library code
    
    template<typename T, typename Callback>
    void draw_some_shape( const rectangle& bounds, Callback function, T& data )
    {
        for( int r = bounds.top; r < bounds.bottom; ++r )
            for( int c = bounds.left; c < bounds.right; ++c )
                if( inside( r, c ) )
                    function( r, c, data );
    }
    
    // client code
    
    struct image_data
    {
        int image[ HEIGHT ][ WIDTH ], color;
    };
    
    void draw_pixel( int row, int column, image_data& data )
    {
        image_data.image[ row ][ column ] = image_data.color;
    }
    
    int main( void )
    {
        image_data data;
        data.color = hsv( 0.333, 0.5, 0.5 );
        rectangle bounds;
        bounds.top = HEIGHT / 2;
        bounds.left = WIDTH / 2;
        bounds.bottom = HEIGHT;
        bounds.right = WIDTH;
        draw_some_shape( bounds, draw_pixel, data );
        // do something useful with the image
        return 0;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This can be avoided with template, as shown below:
    Code:
    // library code
    
    template<typename T, typename Callback_t>
    void draw_some_shape( rectangle* bounds, Callback_t function, T& data )
    {
        for( int r = bounds->top; r < bounds->bottom; ++r )
            for( int c = bounds->left; c < bounds->right; ++c )
                if( inside( r, c ) )
                    callback( r, c, data );
    }    
    
    // client code
    
    struct image_data
    {
        int image[ HEIGHT ][ WIDTH ], color;
    };
    
    void draw_pixel( int row, int column, image_data* data )
    {
        image_data->data[ row ][ column ] = image_data->color;    
    }
    
    int main()
    {
        image_data data;
        data.color = hsv( 0.333, 0.5, 0.5 );
        rectangle bounds;
        bounds.top = HEIGHT / 2;
        bounds.left = WIDTH / 2;    
        bounds.bottom = HEIGHT;
        bounds.right = WIDTH;
        draw_some_shape( &bounds, &draw_pixel, &data );
        // do something useful with the image
        return 0;
    }
    There is little excuse for void* in C++, except for calling C functions.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Elysia View Post
    This can be avoided with template, as shown below:
    The method you and Laserlight are talking about is definitely a good one, but it still, in theory, allows the possibility for the callback driver to poke around inside the T object when it shouldn't. In practice, this would be extremely difficult because you don't know what's in there, but a void * completely guarantees that the code won't touch it, since it has no idea what type it is (even as a template parameter).

    Normally though, I'd define a callback API like this:

    Code:
    class Callback
    {
    public:
        virtual ~Callback() {}
    
        virtual void DoIt() = 0;
    };
    
    void DriveTheCallback(Callback *cb)
    {
        cb->DoIt();
    }
    The actual callback just inherits from Callback and overrides DoIt().
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, I suppose that may be, but then we would get into X vs Y. Your solution might hide the object, but it's also slower due to being dynamic polymorphism as opposed to static polymorphism.
    It also means more work, but hey, no solution is ever perfect.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Elysia View Post
    Well, I suppose that may be, but then we would get into X vs Y. Your solution might hide the object, but it's also slower due to being dynamic polymorphism as opposed to static polymorphism.
    It also means more work, but hey, no solution is ever perfect.
    Static polymorphism would not allow for loading a plug-in which might implement the callback. Yep, always a tradeoff.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Tags for this Thread