Использование неинициализированного значения в конкатенации (.) или строки в ./Merge_gcov_generalised.pl, строка 226, ‹FILE2›, строка 284046 (#1)

Я написал perl-скрипт для объединения файлов gcov с разных машин. Ниже приведена подпрограмма, которую я написал для слияния.

sub merge_gcov()
    {
        open(FILE1, "<$_[0]") or die "can not open file";
        open(FILE2, "<$_[1]") or die "can not open file";
        open(FILE3, ">$_[2]") or die "can not open file";
        my ($line1, $line2 , $flag );
        while ( 1 )
        {  
            $line1 = <FILE1>; # read them each
            $line2 = <FILE2>;
            last unless ( $line1 || $line2 ); # if both empty exit loop
            #
            # otherwise test for which one just finished
            #
            unless( $line1 )
            {
                $flag = 1;
            last;
            }
            unless( $line2 )
            {
                $flag = 2;
            last
            }   
            #
            # now do the voodo on the two lines
            #
            chomp($line2);
            chomp($line1);
            if($line1=~/^\s*-/ and  $line2 =~/^\s*-/)  
            {   
                print FILE3 "$line1\n";
            }
            elsif($line1=~/^\s*#####/ and  $line2 =~/^\s*#####/) 
            {      
                print FILE3 "$line1\n";
            }
            elsif($line1=~/^\s*#####:\s{0,}(\d{1,})/ and  $line2 =~/^\s{0,}(\d{1,})/) 
            {     
                print FILE3 "$line2\n"
            }
            elsif($line1=~/^\s{0,}(\d{1,})/ and  $line2 =~/^\s*#####:\s{0,}(\d{1,})/) 
            {  
                print FILE3 "$line1\n"
            }
            elsif($line1=~/^\s{0,}(\d{1,})/ and  $line2 =~/\s{0,}(\d{1,})/) 
            { 
                my @values1 =  split(/:/, "$line1");
                my @values2 =  split(/:/, "$line2");
                print FILE3 ("      ",$values1[0]+$values2[0]),":","$values1[1]:","$values1[2]\n";
            }
            else
            {  
                print FILE3 "$line1\n";
                print FILE3 "$line2\n";
             }

        }
    close(FILE3);
    }

Слияние выполнено правильно, но после слияния я получаю ошибку ниже....

Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 284046 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 284414 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 302995 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 311633 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 311962 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 321536 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 323445 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 329553 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 336009 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 336330 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 338188 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 343170 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 349037 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 349610 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 633937 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 634509 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 634877 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 653458 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 662096 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 662425 (#1)
Use of uninitialized value in concatenation (.) or string at
        ./Merge_gcov_generalised.pl line 226, <FILE2> line 671999 (#1)
Use of uninitialized value in concatenation (.) or string at

Я знаю, что не получаю эти предупреждения, когда использую нет предупреждений, но есть ли другой способ удалить эти предупреждения.

Строка 226:print FILE3 (" ",$values1[0]+$values2[0]),":","$values1[1]:","$values1[2]\n";< /сильный>


person Nethra    schedule 18.01.2013    source источник
comment
На ваш код больно смотреть. Только в первых трех строчках 5 ошибок. :-(   -  person melpomene    schedule 18.01.2013
comment
{0,} он же *, и {1,} он же +. Что с обфускацией?   -  person TLP    schedule 18.01.2013
comment
Эти предупреждения означают, что либо $values1[1], либо $values1[2] не определены. Это означает, что ваш раскол дает слишком мало элементов, чтобы заполнить массив так далеко. Таким образом, это признак того, что ваши данные повреждены или что у вас есть крайние случаи, которые ломают ваш парсер. Проверьте ввод для этих строк и посмотрите, как обрабатывать эти крайние случаи.   -  person TLP    schedule 18.01.2013


Ответы (2)


Если все, что вы хотите сделать, это избавиться от этого конкретного предупреждения, которое вы уже ожидаете и учитываете, то все, что вам нужно сделать, это следующее:

{    no warnings 'uninitialized';
     # **Small** bit of code causing the problem.
     say "A string and $probably_undefined";
}

Причина, по которой я подчеркиваю маленький код, заключается в том, что в Perl нет тысячи категорий предупреждений, которые можно включать и выключать с помощью прагмы. У него есть несколько довольно широких категорий, которые, если вы оставите безоружными слишком большое пространство, укусят вас. Идея состоит в том, чтобы посмотреть на каждое условие предупреждения и решить, не имеет ли неинициализированное значение никакого эффекта или, по крайней мере, можно объяснить.

person Axeman    schedule 18.01.2013

Вы проверяете неинициализацию одной или другой строки, но вы никогда не используете эту информацию, поэтому вы печатаете undef, соединенный с новой строкой, в вашем финальном else; это источник ваших предупреждений.

В ваших файлах gcov на самом деле есть куча лишних строк новой строки, вызванных тем, что один файл заканчивается первым, по одному на каждую несопоставленную строку. Они действительны только потому, что gcov либо очень снисходительно относится к тому, что он принимает, либо потому, что gcov прекращает молча читать ввод, когда видит первую пустую новую строку. Первый великолепен; второй очень плохой.

Чтобы исправить это, нам нужно выяснить, где мы ожидаем найти undef и что делать, когда мы его найдем. Этот код может генерировать undef в $line1 и $line2, когда мы доходим до конца каждого файла. Давайте посмотрим, как вы их используете, чтобы увидеть, где undef в порядке, а где нет.

  1. Проверка на ложность обеих строк (например, undef): это хорошее использование undef.
  2. Настройка $flag: хорошее использование, но плохая логика, поскольку вы больше никогда не используете $flag.
  3. Совпадение с шаблоном: хорошее использование, потому что сопоставление с шаблоном ничего не должно (и не работает) не сработать, и это правильно для вашего кода.
  4. Печать строки, которая может быть undef: плохое использование, так как это сгенерирует ваше предупреждение и выведет дополнительную пустую новую строку.

Поскольку все совпадения с шаблоном не будут соответствовать undef, вы можете просто пропустить код, который устанавливает $flag, и сделать последнее else таким:

...
else {
    # One or the other file has run out already. Note that
    # the $line variables being undef here is OK because that's
    # an expected possible value that we're actually testing for.
    # We could used "defined $lineX" but since undef itself is 
    # false, this is okay.
    print FILE3 "$line1" if $line1;
    print FILE3 "$line2" if $line2;
}

А теперь немного undef философствования.

Предупреждение о неинициализированной переменной почти всегда является логической ошибкой, несмотря на то, что Perl любезно исправляет это. Если вы получаете их, вы должны искать следующее:

  1. Я вызываю что-то, что возвращает undef? Если да, то я называю это неправильно или с неверными параметрами? Могу ли я заменить значение по умолчанию, чтобы оно не было ошибочным, например, 0 или '' (используя оператор Defined-or //), если мой вызов действителен? Нужна ли мне таблица или подпрограмма, чтобы вместо этого давать мне значения по умолчанию? Если я не могу использовать значение по умолчанию, что не так с моей логикой?
  2. Если это не так, ссылаюсь ли я на неинициализированный массив или хеш-запись? Perl автоматически оживит эти записи и установит для них значение undef. Мой индекс или ключ плохие? Если нет, должен ли я сам устанавливать для этих записей значение по умолчанию, проверять границы моего индекса для массива или проверять, соответствует ли хеш-элемент exists хэшу? В противном случае применяются критерии 1.
  3. Если ни один из них не имеет места, у меня есть неинициализированная скалярная переменная. Почему не инициализируется? Чем я должен был его инициализировать? Какое предположение я забыл сделать (не инициализировав скаляр известным значением)?

Вообще говоря, если ваш код не должен выдавать предупреждение (например, вы добавили к нему warn), предупреждение означает, что что-то не так, как вы ожидали. Вы должны посмотреть на это и понять, почему, а не просто скрыть диагностику.

person Joe McMahon    schedule 23.09.2014