Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re: [XS] Weird behaviour on some Linux systems

by jcb (Vicar)
on Oct 10, 2019 at 22:09 UTC ( #11107327=note: print w/replies, xml ) Need Help??


in reply to [XS] Weird behaviour on some Linux systems

Please check what the NVgf macro expands to on the different platforms and check what ANSI C and POSIX say that conversion is supposed to actually do.

Replies are listed 'Best First'.
Re^2: [XS] Weird behaviour on some Linux systems
by syphilis (Bishop) on Oct 11, 2019 at 01:45 UTC
    Please check what the NVgf macro expands to on the different platforms ....

    The puzzle is that, for certain cases (ie the aforementioned Debian and Ubuntu builds of perl) it apparently expands to different things, depending upon how it is expanded.
    I find that mostly:
    sprintf(buff, "%.19" NVgf, SvNV(arg)); and sv_setpvf(keysv, "%.19" NVgf, SvNV(arg));
    produce the same result.
    That is, the string in "buff" is exactly the same as the string in the PV slot of "keysv".
    However, on some systems, with perls whose NV is 'double', and for integer values that require more than 17 digits, the string in "buff" differs from the string in the PV slot of "keysv".

    Corion has suggested that this might be explained in terms of differences between perl's sprintf() and libc's sprintf().
    My only reason for doubting him is that in 15 years of fiddling around with (s)printf on these systems, I have encountered no such issue. (But as soon as I start trying to get NVgf to work as I expect with sv_setpvf, I hit issues.)

    ... and check what ANSI C and POSIX say that conversion is supposed to actually do

    Yes ... I've had no luck in finding any info on "NVgf" anywhere.
    However, I've just found that replacing:
    sv_setpvf(keysv, "%.19" NVgf, SvNV(arg)); with sv_setpvf(keysv, "%.19g", SvNV(arg));
    makes no difference at all (at least when NV is 'double').
    Given that I reckon I know what "%.19g" should expand to, this would suggest that I don't really need to wonder about what NVgf expands to - rather concentrate more on what sv_setpvf is doing (and on Corion's suggestion).
    Or just settle for the workaround that I've already got :-)

    Cheers,
    Rob

      NVgf is part of Perl, not ANSI C or POSIX. It is a preprocessor macro that, from context, must expand to a string constant that completes a printf conversion sequence. What does sv_setpvf(keysv, "NVgf: \"%s\"", NVgf) produce? (That might produce an error; I am guessing that sv_setpvf behaves like C sprintf but puts the result into a Perl SV.) From context, that must be a printf conversion character; what do ANSI C and POSIX say that character is supposed to do?

        I think we can forget all about "NVgf". It has nothing to do with the problem.
        Below is a shorter, clearer demonstration of the issue - one that makes no mention of "NVgf".

        It's really only of interest when run on a perl whose perl -V:nvsize is 8.
        If anyone can get this script to pass its test on such a perl on Ubuntu, then I'd love to see the perl -V output and also the Ubuntu version number.
        use strict; use warnings; use Test::More tests => 1; use Inline C => Config => BUILD_NOISY => 1, ; use Inline C => <<'EOC'; SV * foo(SV * arg, int if_branch) { SV * keysv; char buff[32]; keysv = NEWSV(0, 32); /* Make sure arg is an NV */ if(!SvNOK(arg)) croak("Not a valid arg for this demo"); if(if_branch) { sv_setpvf(keysv, "%.19g", SvNV(arg)); } else { sprintf(buff, "%.19g", SvNV(arg)); sv_setpvf(keysv, "%s", buff); } return keysv; } EOC my $d = 2 ** 63; my $if = foo($d, 1); # uses if branch my $else = foo($d, 0); # uses else branch is($if, $else, 'they are the same');
        I can see only 2 possible explanations for the test failing:
        1) it's a bug in the way that sv_setpvf assigns the string to the SV;
        2) it's something that I haven't yet thought of

        I've gone cold on the notion that there's something invalid about using sprintf in the XS environment.
        It's the one that's delivering the sane result, agreeing both with what happens in the C environment and with what I expect.

        I'll ultimately post that demo script in a bug report to RT (and provide a link to it here) unless someone can convince me that there's no perl bug.

        I am guessing that sv_setpvf behaves like C sprintf but puts the result into a Perl SV

        Yes, that's right - sprintf writes to a string buffer, sv_setpvf writes directly to the SV's PV slot.
        The perlclib documentation specifically recommends using sv_setpvf instead of sprintf, which would not be very good advice if sv_setpvf is buggy.

        Cheers,
        Rob

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2021-01-16 12:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?