Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re^2: Passing integer pointer in XS?

by martin67 (Novice)
on Jul 18, 2016 at 20:56 UTC ( #1168004=note: print w/replies, xml ) Need Help??


in reply to Re: Passing integer pointer in XS?
in thread Passing integer pointer in XS?

Thank you! This looks interesting - and definately a new area of Perl for me... I tried to compile it but ran into an error:
TellStick.xs:70:10: error: ‘sv’ undeclared (first use in this function +)
I guess sv needs to be declared. And there was a typo for NewSViv. So now it looks like
if (rv == TELLSTICK_SUCCESS) { HV* hv = newHV(); SV *sv = newSV(0); sv = newSVpv(protocol, 0); hv_stores(hv, "protocol", sv); sv = newSVpv(model, 0); hv_stores(hv, "model", sv); sv = newSViv(id); hv_stores(hv, "id", sv); sv = newSViv(dataTypes); hv_stores(hv, "dataTypes", sv); RETVAL = newRV_noinc(hv); } else { RETVAL = &PL_sv_undef; }
There were some compilation warnings as well, don't know if they are important:
In file included from /usr/lib/arm-linux-gnueabihf/perl/5.20/CORE/perl +.h:5102:0, from TellStick.xs:2: TellStick.xs: In function ‘XS_TellStick_tdSensor’: TellStick.xs:76:31: warning: passing argument 2 of ‘Perl_newRV_noinc’ +from incompatible pointer type RETVAL = newRV_noinc(hv); ^ /usr/lib/arm-linux-gnueabihf/perl/5.20/CORE/embed.h:371:48: note: in d +efinition of macro ‘newRV_noinc’ #define newRV_noinc(a) Perl_newRV_noinc(aTHX_ a) ^ In file included from /usr/lib/arm-linux-gnueabihf/perl/5.20/CORE/perl +.h:5061:0, from TellStick.xs:2: /usr/lib/arm-linux-gnueabihf/perl/5.20/CORE/proto.h:2874:19: note: exp +ected ‘struct SV * const’ but argument is of type ‘struct HV *’ PERL_CALLCONV SV* Perl_newRV_noinc(pTHX_ SV *const sv)
But the code works!!!

I get the correct values:

protocol: mandolyn, model: temperaturehumidity, sensorId: 51, dataType +s: 3 protocol: mandolyn, model: temperaturehumidity, sensorId: 61, dataType +s: 3
Thank you very much for your help! Now I have a way forward for implementing the rest of fucntion in the C library.

Replies are listed 'Best First'.
Re^3: Passing integer pointer in XS? (XS << Perl)
by tye (Sage) on Jul 18, 2016 at 21:10 UTC

    This is the kind of code that, in my experience, is one of the most likely sources of particularly troublesome errors/bugs. If you want to provide a Perlish interface, then I'd implement that in Perl code, not in XS code.

    If you are having to deal with reference counts, for example, then you are highly likely to get it wrong sooner rather than later and more than once and probably not always notice the problem before you release the code.

    Just write a tiny wrapper function in mundane Perl code and have that call the very, very thinly wrapped XS that calls the C code. Only do in XS those things that you really have to do in XS.

    - tye        

      What would be simpler than returning them in a hash? ...oh yeah, returning them in a list! Here ya go.
      void tdSensor() CODE: { char protocol[_MAX_PROTOCOL_LEN + 1]; char model[_MAX_MODEL_LEN + 1]; int id; int dataTypes; int rv = tdSensor( protocol, sizeof(protocol), model, sizeof(model), &id, &dataTypes ); if (rv != TELLSTICK_SUCCESS) { XSRETURN(0); } EXTEND(SP, 4); ST(0) = sv_2mortal(newSVpv(protocol, 0))); ST(1) = sv_2mortal(newSVpv(model, 0)); ST(2) = sv_2mortal(newIV(id)); ST(3) = sv_2mortal(newIV(dataTypes)); XSRETURN(4); }

      Usage:

      use feature qw( say ); while (my ($protocol, $model, $id, $dataTypes) = tdSensor()) { say join ', ', "protocol: $protocol", "model: $model", "sensorId: $id", "dataTypes: $dataTypes"; }

      Untested.

        If the first 4 arguments are for specifying ways to output 2 strings, then you can get simpler than that!

        int tdSensor( protocol, protocolLen, model, modelLen, id, dataTypes ) SV * protocol int protocolLen SV * model int modelLen int & id int & dataTypes CODE: { STRLEN n_a; (void) SvPV_force( protocol, n_a ); (void) SvPV_force( model, n_a ); SvGROW( protocol, protocolLen ); SvGROW( model, modelLen ); } RETVAL = tdSensor( SvPV(protocol), protocolLen, SvPV(model), modelLen, &id, &data +Types ); SvCUR_set( protocol, strlen(SvPV(protocol)) ); SvCUR_set( model, strlen(SvPV(model)) ); OUTPUT: RETVAL id dataTypes

        But much simpler (and less likely to be buggy) than even that is:

        int _tdSensor( protocol, protocolLen, model, modelLen, id, dataTypes ) char * protocol int protocolLen char * model int modelLen int & id int & dataTypes CODE: RETVAL = tdSensor( protocol, protocolLen, model, modelLen, &id, &d +ataTypes ); OUTPUT: RETVAL id dataTypes

        Plus

        sub tdSensor { my( $protocolLen, $modelLen ) = @_; $protcolLen ||= 1024; $modelLen ||= 1024; my $protocol = '\0' x $protcolLen; my $model = '\0' x $modelLen; my $id = 0; my $dataTypes = 0; my $ret = _tdSensor( $protocol, $protocolLen, $model, $modelLen, $id, $dataTypes ); s/\0.*// for $protocol, $model; return( $ret, $protocol, $model, $id, $dataTypes ); }

        Which has the significant advantage of making it much easier to improve the interface without having to futz with the super finicky XS part of the code.

        - tye        

Re^3: Passing integer pointer in XS?
by ikegami (Patriarch) on Jul 18, 2016 at 21:18 UTC

    SV *sv = newSV(0); leaks. You want SV *sv;

    The other issue is because I forgot to cast it. newRV_noinc(hv) should be newRV_noinc(MUTABLE_SV(hv)).

    Fixed in original.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1168004]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2022-12-01 07:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?