Неожиданный возврат, отличный от NULL - PullRequest
2 голосов
/ 10 декабря 2010

Я играю с TagLib (на Windows, построенной с MingW). Я пытаюсь заставить TagLib распознавать, когда в файле MP3 нет информации ID3v1 или ID3v2. Согласно документации TagLib , функция ID3v2Tag () в объекте MPEG File должна возвращать указатель NULL, если в файле нет информации ID3v2.

К сожалению, этого не происходит. У меня есть несколько тестовых MP3-файлов, которые я использую в своем коде (я сделал файлы доступными):

  • blank.mp3 ( download ), без информации ID3v1 или ID3v2. Я могу подтвердить это, выполнив простой текстовый поиск «TAG» и «ID3» в двоичном содержимом файлов.
  • only_album_id3v2.mp3 ( скачать ), содержит информацию ID3v2 (установлен только альбом)
  • only_album_id3v1.mp3 ( скачать ), содержит информацию ID3v1 (установлен только альбом)

Вот мой код.

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    cout << at->album() << endl;
    cout << bt->album() << endl;
    cout << ct->album() << endl;

    cout << "The program is done.";

    return 0;
}

Запуск этой программы должен прерваться из-за ошибки указателя NULL на cout << at->album() << endl;, но она работает просто отлично. Кроме того, когда я cout << ct << endl;, он возвращает адрес памяти.

Вот вывод:

Test.

тестовый альбом id3v2

Программа выполнена.

EDIT: Вот новый тест.

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    if(at == NULL)
    {
        cout << "at is NULL.";
    }
    else
    {
        cout << "at is not NULL.";
    }
    cout << endl;

    if(bt == NULL)
    {
        cout << "bt is NULL.";
    }
    else
    {
        cout << "bt is not NULL.";
    }
    cout << endl;

    if(ct == NULL)
    {
        cout << "ct is NULL.";
    }
    else
    {
        cout << "ct is not NULL.";
    }
    cout << endl;

    cout << "The program is done.";

    return 0;
}

А вот и вывод.

Test.
at не NULL.
bt не NULL.
ct не NULL.
Программа выполнена.

Ответы [ 4 ]

5 голосов
/ 10 декабря 2010

Я кратко изучил код TagLib.

Я ничего не знаю об этом и никогда не использовал его, но код кажется мне глючным. И вот почему -

В MPEG :: File :: read () мы ищем тег - d->ID3v2Location = findID3v2();. Если он не существует, он не добавляется в вектор тегов. Это чек - if(d->ID3v2Location >= 0).

Однако в конце функции, перед возвратом, мы имеем -

// Make sure that we have our default tag types available.
ID3v2Tag(true);
ID3v1Tag(true);

Теперь Id3v2Tag(create) с истинным параметром фактически вызывает return d->tag.access(ID3v2Index, create);. Функция доступа () -

template <class T> T *access(int index, bool create)
{
  if(!create || tag(index))
    return static_cast<T *>(tag(index));

  set(index, new T);
  return static_cast<T *>(tag(index));
}

Таким образом, когда create имеет значение true, мы создаем новый пустой тег и помещаем его в вектор (используя функцию set()).

Это означает, что независимо от того, содержит ли файл теги или нет, они добавляются в вектор. Это не задокументированное поведение. Похоже, ошибка.

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

В любом случае, я хочу подчеркнуть, что я никогда не выполнял этот код. Это основано на чисто статическом считывании только очень маленьких частей, без учета больших проблем.

Я думаю, что открытие отчета об ошибке не повредит.

1 голос
/ 10 декабря 2010

Использование нулевого указателя не обязательно приводит к любой ошибке, которую вы видите;это неопределенное поведение.Может показаться, что он работает, или может сделать что-то действительно странное.

В этом случае компилятор, вероятно, генерирует вызов TagLib :: ID3v2 :: Tag :: album с this указатель установлен на ноль, но даже это не гарантируется.Что происходит внутри функции, можно только догадываться.

Если функция может возвращать NULL, вы должны явно проверить это и сделать что-то другое.

0 голосов
/ 15 июля 2011

У меня схожая проблема и, надеюсь, я нашел обходной путь для проверки присутствия ID3v1 / ID3v2.

Это метод virtual bool TagLib::Tag::isEmpty() const

0 голосов
/ 10 декабря 2010

Taglib создает «Пустой» ID3v2Tag и ID3v1Tag в объекте, если у файла их нет.

...