Thread: can't use global variables or funktion parameters

  1. #1
    Registered User
    Join Date
    May 2005
    Posts
    5

    can't use global variables or funktion parameters

    I'm not a good C programmer and run into problems all the time. This is a difficult one. I'm not sure how to explain. I'm doing a nsf (nes sound file) decoder to xmms2 media player.
    xmms2 have the following api for decoder plugins.

    Code:
    static gboolean xmms_nsf_can_handle (const gchar *mimetype);
    static gboolean xmms_nsf_new (xmms_decoder_t *decoder, const gchar *mimetype);
    static gboolean xmms_nsf_decode_block (xmms_decoder_t *decoder);
    static void xmms_nsf_get_media_info (xmms_decoder_t *decoder);
    static void xmms_nsf_destroy (xmms_decoder_t *decoder);
    static gboolean xmms_nsf_init (xmms_decoder_t *decoder);
    xmms2 can use several decoderplugins concurrently and all global variables will then be shared between the threads. There is a fix for this. All methods sends the argument decoder. It is used to get settings for the plugin. xmms_nsf_new looks something like this.

    Code:
    static gboolean
    xmms_nsf_new (xmms_decoder_t *decoder, const gchar *mimetype)
    {
    xmms_nsf_data_t *data;
    data = g_new0 (xmms_nsf_data_t, 1);
    xmms_decoder_private_data_set (decoder, data);
    }
    xmms_nsf_data_t is a struct containing the data for the plugin. My xmms_nsf_data_t looks like

    Code:
    typedef struct xmms_nsf_data_St {
    	NSFHEADER      *tHeader;
    	guint8         uCurrentTrack;
    	guint8         *pCPU;
    	guint32        uCartridgeLength;
    	guint32        uBankswitchingEnabled;
    	guint8         *pCartridge; 
    	/* user settings */
    	gint8          nPan[20];
    	guint8         nOversample; 
    	/* required for 6502 emulation */
    	guint32        dwElapsedTicks;
    	guint32        cyclesRemaining;
    	CONTEXTM6502   m6502; 
    	gboolean       inited; 
    
    } xmms_nsf_data_t;
    When a method need the data is does this

    Code:
    static gboolean
    xmms_nsf_init (xmms_decoder_t *decoder)
    {
    	
    	xmms_nsf_data_t *data;
    	data = xmms_decoder_private_data_get (decoder);
    	...
    }
    This is all well but I use a library called m6502 or make6502 to emulate the 6502 cpu in the nes. I feed it with a function pointer to a function it use to write in the virtual memory like so.

    data->m6502.m6502MemoryRead = tNSFRead;
    data->m6502.m6502MemoryWrite = tNSFWrite;

    The problem is that I need to access my xmms_nsf_data_t in tNSFRead and tNSFWrite to check the nsf header for addon chips. M6502 does not send my xmms_decoder_t along to the read/write functions. How can I access my data?

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Have *Read and *Write access functions to fetch it for you.
    Code:
    tNSFRead( ... )
    {
        somedata instance;
    
        fillinstance( instance )
        ...do whatever...
    }
    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    May 2005
    Posts
    5
    the only functions I know that fetches the data I need is xmms_decoder_private_data_get(decoder); and it needs the xmms_decoder_t. I have looked in the source for some other decoders like flac and vorbis. They have simmilar problems. The libs they use need funktions pointers to callback funktions and they need to use the local data in these funktions. Here is how flac fixes it.

    Code:
    static gboolean
    xmms_flac_new (xmms_decoder_t *decoder, const gchar *mimetype)
    {
    	xmms_flac_data_t *data;
    	data = g_new0 (xmms_flac_data_t, 1);
    
    	data->flacdecoder = FLAC__seekable_stream_decoder_new ();
    	FLAC__seekable_stream_decoder_set_read_callback (data->flacdecoder, flac_callback_read);
    	...
    	FLAC__seekable_stream_decoder_set_client_data (data->flacdecoder, decoder);
    	xmms_decoder_private_data_set (decoder, data);
    	return TRUE;
    }
    Notice the set client data method. When the flac library calls back it does this.

    Code:
    FLAC__SeekableStreamDecoderReadStatus
    flac_callback_read (const FLAC__SeekableStreamDecoder *flacdecoder, FLAC__byte buffer[], guint *bytes, void *client_data)
    {
    	xmms_decoder_t *decoder = (xmms_decoder_t *) client_data;
    	data = xmms_decoder_private_data_get (decoder);
    	...
    }
    it will send the decoders local data back along with it's own arguments. My library can't do this. Are there any other solution?

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I assume you're the one creating these two functions:
    Code:
    data->m6502.m6502MemoryRead = tNSFRead;
    data->m6502.m6502MemoryWrite = tNSFWrite;
    If so, I don't see the problem. Fill it however you like.

    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    May 2005
    Posts
    5
    I don't know how to explain this in any other way. I am creating the tNSFRead and tNSFWrite funktions. tNSFRead looks like this right now.

    Code:
    guint8 tNSFRead(guint32 uAddress, struct MemoryReadByte *pMem)
    {
    	if(uAddress==0x4015) return(mAPURead(uAddress));
    	else if(uAddress>=0x5205 && uAddress<=0x5206  && (data->tHeader->uChips & 0x8))
    		return(mMMC5Read(uAddress));
    	else return(data->pCPU[uAddress]);
    }
    as you can see they need data->tHeader->uChips and data->pCPU but can't access it. I can't make the struct data global because it's a multithreaded enviroment and I can't pass it along to tNSFRead as an argument because tNSFRead is a callback funktion and I can't control the arguments to callback funktions.

  6. #6
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    whats stopping you from using one of the parameters in use already to hide your data. for instance the uint32 which could be used to pass a pointer to a struct containing the real uint32 along with the data structure you need or at least a pointer to it.Messy but im sure could be done.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  7. #7
    Registered User
    Join Date
    May 2005
    Posts
    5
    As I said, tNSFRead is a callback funktion and there is no way to control the arguments to callback funktions. The M6502 library have complete control over them and I would have to change the library to change the arguments.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Arrg! How hard can this be?
    Code:
    tNSFRead( ...whatever... )
    {
        xmms_nsf_data_t fillme;
    
        myownfunctiontofillthis( &fillme, NULL );
    
        ...use it...
    
    }
    Then you do something like this:
    Code:
    void myownfunctiontofillthis( xmms_nsf_data_t *tofill, xmms_nsf_data_t *withthis )
    {
        static xmms_nsf_data_t info;
    
        if( tofill == NULL )
        {
            ...fill 'info' with 'withthis'...
        }
        else
        if( withthis == NULL )
        {
            ...fill 'tofill' with 'info'...
        }
        else
        {
            ...do something else, such as simply display what 'info' has...
        }
    }
    No you can simply call 'myownfunctiontofillthis' from either your tNSFRead or tNSFWrite function after you've already called it some other place, to fetch or set any data you want.

    This isn't even the origional idea I had in mind. There are multiple ways to do the same effect. You just call from within your tNSF* functions whatever function you need to give you your data. It's not a hard concept.

    You do know how to make function calls, right?

    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    Registered User
    Join Date
    May 2005
    Posts
    5
    myownfunctiontofillthis in your example is not a reentrant function and will therefore not work in a multithreaded environment.

    Sense the M6502 library don't have a client data argument to all callback, is seems to be a non-reentrant library and I can't use it. I'll have to find some other library or make one myself

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 08-06-2008, 09:59 AM
  2. Avoiding Global variables
    By csonx_p in forum Windows Programming
    Replies: 32
    Last Post: 05-19-2008, 12:17 AM
  3. Global variables used in a linked class, getting errors.
    By RealityFusion in forum C++ Programming
    Replies: 3
    Last Post: 09-24-2005, 12:25 AM
  4. Use global variables or pointers?
    By RealityFusion in forum C++ Programming
    Replies: 5
    Last Post: 09-22-2005, 08:47 PM
  5. Replies: 6
    Last Post: 01-02-2004, 01:01 PM