1

I am trying to check if an array element is undef from an XSUB like this:

void
print_array(array)
    AV *array

    PREINIT:
        int len;
        SV **sv_ptr;
        SV *sv;
        int i;

    CODE:
        len = av_len(array) + 1;
        printf("[");
        for (i = 0; i < len; i++) {
            sv_ptr = av_fetch( array, i, 0 );
            if (!sv_ptr) {
                printf("empty");
            }
            else {
                sv = *sv_ptr;
                if (sv == &PL_sv_undef) {
                    printf("undef");
                }
                else {
                    printf("*");
                }
            }

            if (i < (len - 1)) {
                printf(", ");
            }
        }

        printf("]\n");

If I run this sub from a Perl script:

use strict;
use warnings;
use ArrayPrint;

my $array = [];
$array->[4] = undef;
ArrayPrint::print_array($array);

The output is:

[empty, empty, empty, empty, *]

Why is the last element not showing undef?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174

1 Answers1

5

An SV can hold an undefined value but still be a different SV than PL_sv_undef. You need to replace the PL_sv_undef test with

SvGETMAGIC(sv);
if (!SvOK(sv)) { printf "undef" } else { printf "*" }
Dave Mitchell
  • 2,193
  • 1
  • 6
  • 7
  • Why is it important to run `SvGETMAGIC()` first? – Håkon Hægland Apr 23 '20 at 11:22
  • @Håkon Hægland, Because you never know the value of a var with get magic before you fetch it. [demo](https://pastebin.com/z969Ee2Y) (`SvGETMAGIC` does nothing if the var has no get magic.) – ikegami Apr 23 '20 at 12:18
  • (and SvOK doesn't just do SvGETMAGIC itself because that would make it harder for each perl op to only trigger magic once for each argument) – ysth Apr 23 '20 at 18:04