意外的非NULL返回

时间:2010-12-10 00:59:55

标签: c++ windows taglib

我正在使用TagLib(在Windows上,使用MingW构建)。我想让TagLib识别MP3文件中没有ID3v1或ID3v2信息。根据{{​​3}},当文件中没有ID3v2信息时,MPEG File对象中的ID3v2Tag()函数应返回NULL指针。

不幸的是,这种情况并未发生。我有一些我在我的代码中使用的测试MP3文件(我已经提供了文件):

  • blank.mp3 TagLib documentation),根本没有ID3v1或ID3v2信息。我可以通过在文件二进制内容中对“TAG”和“ID3”进行纯文本搜索来确认这一点。
  • only_album_id3v2.mp3 download),有ID3v2信息(只设置了相册)
  • only_album_id3v1.mp3 download),有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;
}

由于cout << at->album() << endl;上的NULL指针错误,运行此程序应该会中断,但运行正常。此外,当我cout << ct << endl;时,它返回一个内存地址。

这是输出:

  

测试。

     

测试专辑id3v2

     

程序已经完成。

修改 这是一个新的测试。

#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;
}

这是输出。

  

测试。
  at不是NULL。
  bt不是NULL   ct不是NULL   该计划已经完成。

4 个答案:

答案 0 :(得分:5)

我简要地检查了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)带有true参数,实际上会调用return d->tag.access(ID3v2Index, create);。 access()函数是 -

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为真时,我们正在创建一个全新的空标记并将其放在向量中(使用set()函数)。

这意味着无论文件是否包含标签,都会将它们添加到矢量中。这不是记录在案的行为。看起来像个bug。

我不知道为什么需要这两行 - 看看这个文件的历史可能会暗示它们为什么被添加,但我没有这样做。

无论如何,我想强调我从未真正执行过这段代码。这是基于纯粹静态读取非常小的部分,而不是意识到大规模的问题。

我认为打开错误报告不会有害。

答案 1 :(得分:1)

使用空指针不一定会导致您看到任何错误;这是未定义的行为。它似乎可行,或者它可能会做一些非常奇怪的事情。

在这种情况下,编译器可能会生成对TagLib :: ID3v2 :: Tag :: album的调用,并将 this 指针设置为null,但即使这样也无法保证。函数内部发生的是任何人的猜测。

如果函数可以返回NULL,那么你应该明确地检查它并做一些不同的事情。

答案 2 :(得分:0)

如果文件没有,Taglib会在对象中创建一个“空”ID3v2Tag和ID3v1Tag。

答案 3 :(得分:0)

我遇到了类似问题,希望我找到了ID3v1 / ID3v2状态检查的解决方法。

这是方法virtual bool TagLib::Tag::isEmpty() const