http://qs321.pair.com?node_id=1168008


in reply to Re^3: Passing integer pointer in XS? (XS << Perl)
in thread Passing integer pointer in XS?

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.

Replies are listed 'Best First'.
Re^5: Passing integer pointer in XS? (simpler)
by tye (Sage) on Jul 18, 2016 at 22:14 UTC

    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        

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

      Didn't I already demonstrate that it's quite buggy? (Ok, so you're relying on the fact that manipulating the internal buffer of the scalar works in this situation even though you're not allowed to do it. As far as I'm concerned, you can't call simple something that relies on this level of knowledge of internals.)

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

      Really? Cause I would need to perform some testing to verify that it's correct. All that magic is far far more complicated than just returning the values.

        Check PP(pp_sysread), it does pretty much the same. (Utf8 blah-blah is probably not relevant here.)