Are you using ActiveState or Strawberry Perl? and which version?
It seems that there is a missmatch between what Perl sees as its file descriptor 2 and the C lib file descriptor 2.
use File::Temp qw(tempfile);
use Inline 'C';
open my $olderr, '>&STDERR'; # save STDERR
my ($fh, $fn) = tempfile();
open STDERR, '>&', $fh;
printf "fileno STDERR: %d\n", fileno(STDERR);
print STDERR "foo!";
test_err();
open STDERR, '>&', $olderr; # reset STDERR
close $fh;
open my $e, '<', $fn;
my $err = <$e>;
print "|$err|\n";
__END__
__C__
void test_err() {
FILE *err = fdopen(2, "a+");
(void)fprintf (err, "ERROR");
}
# here it says:
# fileno STDERR: 2
# |foo!|
# ERROR
Besides that, don't trust what you get from Inline::C, the perlio.h header is included before your C code and most stdio functions are replaced by macros calling into perl own implementations (that not-too-unsurprisingly, do not work as expected either):
use strict;
use warnings;
use Inline 'C';
test_err();
__END__
__C__
#define xstr(s) str(s)
#define str(s) #s
void test_err() {
(void)fprintf(stderr, "ERROR goes to " xstr(stderr) "\n");
}
# here, it outputs:
# ERROR goes to (*(*Perl_IStdIO_ptr(((PerlInterpreter *)Perl_get_conte
+xt())))->pStderr)((*Perl_IStdIO_ptr(((PerlInterpreter *)Perl_get_cont
+ext()))))
update: the funny thing is that when a subprocess is launched, perl file descriptors are the ones inherited:
open my $olderr, '>&STDERR'; # save STDERR
my ($fh, $fn) = tempfile();
open STDERR, '>&', $fh;
printf "fileno STDERR: %d\n", fileno(STDERR);
print STDERR "foo!";
test_err();
system "perl -e die";
open STDERR, '>&', $olderr; # reset STDERR
close $fh;
open my $e, '<', $fn;
my $err = <$e>;
print "|$err|\n";
__END__
__C__
void test_err() {
FILE *err = fdopen(2, "a+");
(void)fprintf (err, "ERROR");
}
# fileno STDERR: 2
# |foo!Died at -e line 1.
# |
# ERROR