意外的非NULL返回

问题描述:

我正在玩TagLib(在Windows上,使用MingW构建)。我试图让TagLib识别MP3文件中没有ID3v1或ID3v2信息。根据TagLib documentation,当文件中没有ID3v2信息时,MPEG File对象中的ID3v2Tag()函数应该返回一个NULL指针。意外的非NULL返回

不幸的是,这没有发生。我有我做了,我在我的代码中使用了一些测试MP3文件(我已提供的文件):

  • blank.mp3download),没有的ID3v1和ID3v2的信息都没有。我可以通过在文件二进制内容中对“TAG”和“ID3”进行纯文本搜索来确认这一点。
  • only_album_id3v2.mp3download),具有ID3v2的信息(只有专辑设置)
  • only_album_id3v1.mp3download),具有的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;,但它运行得很好。另外,当我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。
程序完成。

+0

你期望什么?例外?如果我正确地看到了,则会将NULL值传递给流,而流不会在控制台中输出。这不是预期的吗? – Kissaki 2010-12-10 02:13:34

+0

程序是否完成?真的输出?因为我没有看到你的源代码。 – Kissaki 2010-12-10 02:15:13

+0

@Kissaki,不应该`cout 2010-12-10 04:47:54

我简单地检查了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是真的,我们正在创造一个全新的,空标签和(使用set()功能),将其放置在载体中。

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

我不知道为什么需要这两条线 - 查看此文件的历史记录可能暗示为什么添加它们,但我没有这样做。

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

我认为打开一个bug报告不会伤害。

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

在这种情况下,编译器可能会生成对TagLib :: ID3v2 :: Tag :: album的调用,这个指针设置为null,但即使这样也不能保证。这个功能里面发生的事情是任何人的猜测。

如果该函数可以返回NULL,则应该明确地检查它并执行一些不同的操作。

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

我有simmilar问题,希望我已经找到ID3v1/ID3v2存在检查的解决方法。

它的方法virtual bool TagLib::Tag::isEmpty() const