gnc_numeric function pointer casts

Derek Atkins warlord at MIT.EDU
Thu Jul 15 17:58:55 EDT 2004


Neil Williams <linux at codehelp.co.uk> writes:

> casts are getting to be the major problem in my code!

Only because you don't understand function pointers.  ;)
I suggest you read up on them, and then you'll understand
what's going on and why your code is crapping out...

> In the:
> Re: scheduled transactions make bad transactions with 1.8.9 ?
> thread Tue, 22 Jun 2004, Derek, you advised:
>
>> You should cast the function-pointer first and then things will
>> be happy:
>> 
>>    gnc_numeric (*numeric_getter)(gpointer) = lister->param_getfcn;
>>    gnc_numeric qtb = numeric_getter(mergeEnt);
>
> I've had to concentrate on my other projects since then but I'm trying to 
> understand why this doesn't work for me.

Ok, the first line is creating a function pointer, numeric_getter,
which points to a function that takes one argument (a gpointer) and
returns a gnc_numeric.  The second line calls the numeric_getter with
the mergeEnt and assigns the resulting gnc_numeric to qtb.

> Without parameters, that first line won't compile:
> warning: initialisation from incompatible pointer type

Ahh, that's because the function pointer is of a different type.
So, it needs a cast...  But...

> So I'm trying:
> gnc_numeric (*numeric_getter)(gpointer,gpointer) = 
> lister->param_getfcn(mergeEnt, lister);
> qtn = numeric_getter(mergeEnt,lister);

Ok, do you understand the difference between "lister->param_getfcn"
and "lister->param_getfcn(a,b)"?  I don't think you do.  The former
returns a pointer to the function.  The latter calls the function and
returns the value returned by the function.

> or
> gnc_numeric (*numeric_getter)(QofEntity*, QofParam*);
> numeric_getter = lister->param_getfcn(mergeEnt, lister);
> qtn = numeric_getter(mergeEnt, lister);
> qtnd = gnc_numeric_to_double(qtn);

This is just as wrong.

> This compiles but segfaults.
> The variables are defined as:
> QofParam *lister
> QofEntity* mergeEnt
>
> (I've also tried with just one gpointer and just mergeEnt.)
>  as well as (*numeric_getter)(QofEntity*, QofParam*)

try this:

  gnc_numeric (*numeric_getter)(QofEntity*, QofParam*) = 
              (gnc_numeric (*)(QofEntity*, QofParam*)) lister->param_getfcn;

(feel free to break this up into two lines).  What this does is:

1) define a variable, numeric_getter, which is a pointer to a function
   that takes two arguments (a QofEntity* and a QofParam*) and returns
   a gnc_numeric.
2) assigns this variable to the function pointer lister->param_getfcn...
3) after casting that function-pointer to the appropriate form.

Then you can call numeric_getter(mergeEnt, lister) to obtain the gnc_numeric.

> I know I've got the casts wrong (again) and I too wish this could have been 
> done with C++!
> http://www.codehelp.co.uk/code/gncBookMerge.c
> http://www.codehelp.co.uk/code/gncBookMerge.h
>
> (In the code, other types also use these function pointers but it doesn't seg 
> fault because there isn't any real data in the test GNCBook* for those 
> parameter types.) I've used xaccMallocAccount to create two accounts, so all 
> the account balances should be zeroed, I've used BeginEdit and SetType. I've 
> used SetName and SetDescription.

It also doesn't seg-fault because you can exchange pointers for each
other just fine, but you can't exchange a gnc_numeric for a pointer.
This is why cast-order is important.

> The GUID is fine.
>
> Which leads me to another point:
> In my function, I want to accept an import GNCBook* and access the existing 
> book - the actual import of the data to create the import GNCBook is done 
> elsewhere. When I test the code, I create a testbook, test accounts, etc., 
> and a GUID is always created.
> Therefore,
> If the GUID matches, the import data must have come from a real, existing, 
> book, like a closed book or archived book, etc. - the same semantic object, 
> etc. because GUID's are unique.
> If the GUID doesn't match, the import data could have come from anywhere.
> Am I correct to assume the above AND that my function will NEVER receive a 
> blank, null, invalid or unset GUID for any object?

Correct on all counts.  If the GUID matches then you know it's the
same semantic object.  However if the GUID does NOT match then you
have no information about the object, it could still be the same
sematic object that was imported from a non-gnucash source (e.g.  the
importer assigned a new GUID to the same semantic object).

Hopefully I didn't just confuse you more..

-derek

-- 
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       warlord at MIT.EDU                        PGP key available


More information about the gnucash-devel mailing list