Hello All,

I use two APIs a lot in my code. What I have found is that each creates a lot of synomys for the standard C Types with a bunch of typedefs. For example:
numeric types: IV, I32, UV, U32, I16, U16, my_ulonglong, my_bool (just a char)
string length: STRLEN (in addition to size_t or plain unsigned long)

What makes things more interesting is that most of one of the APIs is macros. In particular, some of the macros rely on the caller to get the return type right. (The result might be supposed to be an SV *, AV *, HV * ...)

I haven't been able to find a good resource outlining when you need/should actually cast. I'm fairly sure that simple assignments and normal function calls (where prototypes exist) never need to be casted. For example, assigning something of type STRLEN/my_ulonglong to an int will not need a cast (assuming the value fits into the int), right? Also, a function return values and input values don't need to be casted, right?

However, with macros and variable argument functions, it becomes a bit more confusing. Arguments to macros presumably need to be cast to the right type explicitly. But this isn't always possible as some macros expand to junks of code, using the input like a variable.

Thanks for any input. Below is just an example of what some code looks like before preprocessing and after (mainly just to show the number of typecasts per square cm).

Code:
XS(XS_Mytest4_p_test_func)
{
    dXSARGS;
    {
    char *string_buffer;
    STRLEN len = 0;
    int    RETVAL;
    dXSTARG;
    if(items != 1)
      XSRETURN_UNDEF;
    if(!SvROK(ST(0))  || SvMAGICAL(ST(0)) || SvAMAGIC(ST(0)))
      XSRETURN_UNDEF;
    if(SvTYPE(SvRV(ST(0))) == SVt_PV) {
      string_buffer = SvPV((SV *)SvRV(ST(0)), len);
    } else if (SvTYPE(SvRV(ST(0))) == SVt_PVAV) {
      /* must cast to AV presumably. Couldn't cast len here if it were an int  */
      string_buffer = SvPV(*av_fetch((AV *)SvRV(ST(0)), 0, 0), len);
      /* Getting 1st ele of array. Normally check that it can be used as a string - left 
         out to keep code example small.                                                */
    }
    /* do something with string_buffer and len */
    RETVAL = len;
    XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}
After preprocessing (not formatted properly. fyi only...)
Code:
void XS_Mytest4_p_test_func(register PerlInterpreter *my_perl __attribute__((unused)), CV* cv __attribute__((unused)))
{
    register SV **sp = (*Perl_Tstack_sp_ptr(my_perl)); I32 ax = (*(*Perl_Tmarkstack_ptr_ptr(my_perl))--); register SV **mark = (*Perl_Tstack_base_ptr(my_perl)) + ax++; I32 items = sp - mark;
    {
# 15 "Mytest4.xs"
    char *string_buffer;
    STRLEN len = 0;
# 30 "Mytest4.c"
 int RETVAL;
 SV * const targ = (((*Perl_Top_ptr(my_perl))->op_private & 32) ? ((*Perl_Tcurpad_ptr(my_perl))[(*Perl_Top_ptr(my_perl))->op_targ]) : Perl_sv_newmortal(my_perl));
# 18 "Mytest4.xs"
    if(items != 1)
      (void)( { ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)] = &(*Perl_Isv_undef_ptr(my_perl))); (void)( { IV tmpXSoff = (1); (*Perl_Tstack_sp_ptr(my_perl)) = (*Perl_Tstack_base_ptr(my_perl)) + ax + (tmpXSoff - 1); return; } ); } );
    if(!(((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_flags & 0x00080000) || (((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_flags & (0x00002000|0x00004000|0x00008000)) || (((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_flags & 0x10000000))
      (void)( { ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)] = &(*Perl_Isv_undef_ptr(my_perl))); (void)( { IV tmpXSoff = (1); (*Perl_Tstack_sp_ptr(my_perl)) = (*Perl_Tstack_base_ptr(my_perl)) + ax + (tmpXSoff - 1); return; } ); } );
    if(((((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv)->sv_flags & 0xff) == SVt_PV) {
      string_buffer = ((((SV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv)->sv_flags & (0x00040000)) == 0x00040000 ? ((len = ((XPV*) ((SV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv)->sv_any)->xpv_cur), ((XPV*) ((SV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv)->sv_any)->xpv_pv) : Perl_sv_2pv_flags(my_perl, (SV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv,&len,2));
    } else if (((((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv)->sv_flags & 0xff) == SVt_PVAV) {
      string_buffer = (((*Perl_av_fetch(my_perl, (AV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv,0,0))->sv_flags & (0x00040000)) == 0x00040000 ? ((len = ((XPV*) (*Perl_av_fetch(my_perl, (AV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv,0,0))->sv_any)->xpv_cur), ((XPV*) (*Perl_av_fetch(my_perl, (AV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv,0,0))->sv_any)->xpv_pv) : Perl_sv_2pv_flags(my_perl, *Perl_av_fetch(my_perl, (AV *)((XRV*) ((*Perl_Tstack_base_ptr(my_perl))[ax + (0)])->sv_any)->xrv_rv,0,0),&len,2));


    }

    RETVAL = len;
# 47 "Mytest4.c"
 (sp = (*Perl_Tstack_base_ptr(my_perl)) + ax - 1); (void)( { Perl_sv_setiv(my_perl, targ,(IV)((IV)RETVAL)); (void)( { (void)( { if (((targ)->sv_flags & 0x00004000)) Perl_mg_set(my_perl, targ); } ); (*++sp = (targ)); } ); } );
    }
    (void)( { IV tmpXSoff = (1); (*Perl_Tstack_sp_ptr(my_perl)) = (*Perl_Tstack_base_ptr(my_perl)) + ax + (tmpXSoff - 1); return; } );
}