... something in your @HR is coming up as an undef.
I was going to write that a simple empty array could also produce an "... uninitialized value in printf ..." warning, but warnings apparently got a little bit smarter in version 5.12:
c:\@Work\Perl>perl -wMstrict -le
"print 'perl version ', $];
;;
my @HR;
;;
printf qq{A: %s \n}, @HR;
;;
++$#HR;
printf qq{B: %s \n}, @HR;
"
perl version 5.008009
Use of uninitialized value in printf at -e line 1.
A:
Use of uninitialized value in printf at -e line 1.
B:
perl version 5.010001
Use of uninitialized value in printf at -e line 1.
A:
Use of uninitialized value in printf at -e line 1.
B:
perl version 5.012003
Missing argument in printf at -e line 1.
A:
Use of uninitialized value in printf at -e line 1.
B:
perl version 5.014004
Missing argument in printf at -e line 1.
A:
Use of uninitialized value in printf at -e line 1.
B:
(See 'Missing argument in %s' in perldiag in version 5.12 and after.)
Update: Posted this reply before seeing other, closely related replies: this from Monk::Thomas and this from hippo.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Yeah, with 5.8.x, the warnings are indistinguishable. And thanks for pointing out that the empty array will also create that error: my errcheck_array() didn't handle the empty array condition.
Further, while both my method and the BrowserUk/stevieb method will help you find what's wrong, neither will help sanitize the input to prevent the warning in a live-system (for example, if you need your debug logging live until the unlikely data triggers it, but you still need the production code to set a reasonable value for $EVmsg): it's safer in production code to try to sanitize the input, to prevent such a condition from affecting your users. For that, you could wrap an error-checker-and-sanitizer around the sprintf command, or otherwise sanitize before running the sprintf. This example has a wrapper sprintf_prevent_error() and a sanitize() function which cleans and logs, but keeps the sprintf separate:
use warnings;
use strict;
use Log::Any qw($log);
use Log::Any::Adapter ('File', './debug.log', log_level => 'debug');
sub sprintf_prevent_error {
my $format = shift;
my @a = @_;
# if there isn't a format, log an error message and return an erro
+r string
# might want to return undef instead, and check $EVmsg for undef
+ before blindly doing anything else with it...
unless(defined $format) {
$log->debugf("sprintf('%s',%s): format is not defined", $forma
+t, \@_);
return "<WARNING: sprintf format not defined>";
}
# if there aren't any arguments, the array is undefined; log an er
+ror message and return an error string
# might want to return undef instead, and check $EVmsg for undef
+ before blindly doing anything else with it...
unless(@a) {
$log->debugf("sprintf('%s',%s): array is empty", $format, \@_)
+;
return "<WARNING: array is empty>";
}
# count the number of undefined elements in input array, and log t
+he error message
# but _don't_ return; we will sanitize the inputs and continue t
+o create the sprintf
my $count = grep {!defined} @a;
$log->debugf("sprintf('%s',%s): sanitizing %d undefined values", $
+format, \@_, $count) if $count;
# sanitizes the input: replace any undefined elements with the emp
+ty string
$_//='' for @a;
# return the final sprintf of the sanitized input
sprintf $format, @a;
}
sub sanitize {
$log->debugf("sanitize(%s): calling", \@_);
unless(@_) {
# log and return if there's nothing to sanitize
$log->debugf("sanitize(%s): nothing to sanitize", \@_);
return;
};
my $count = grep {!defined} @_; # count the undefined argument
+s
$log->debugf("sprintf(%s): sanitizing %d undefined values", \@_, $
+count) if $count;
$_//='' for @_;
}
foreach my $hr ( [qw(a b c)], [d => undef, e => undef, 'f'], [qw(x y z
+)], [] ) {
my @HR = @$hr;
my $DIcas_text = @HR ? '%s' . ',%s'x$#HR : 'empty array format';
my $EVmsg = sprintf_prevent_error($DIcas_text, @HR);
print "STD OUTPUT> $EVmsg\n";
$EVmsg = sprintf_prevent_error(undef, @HR);
print "STD OUTPUT> $EVmsg\n";
sanitize($DIcas_text, @HR);
$EVmsg = sprintf($DIcas_text, @HR);
}
| [reply] [d/l] [select] |