意外的非NULL返回
我正在玩TagLib(在Windows上,使用MingW构建)。我试图让TagLib识别MP3文件中没有ID3v1或ID3v2信息。根据TagLib documentation,当文件中没有ID3v2信息时,MPEG File对象中的ID3v2Tag()函数应该返回一个NULL指针。意外的非NULL返回
不幸的是,这没有发生。我有我做了,我在我的代码中使用了一些测试MP3文件(我已提供的文件):
- blank.mp3(download),没有的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;
,但它运行得很好。另外,当我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。
程序完成。
我简单地检查了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。
你期望什么?例外?如果我正确地看到了,则会将NULL值传递给流,而流不会在控制台中输出。这不是预期的吗? – Kissaki 2010-12-10 02:13:34
程序是否完成?真的输出?因为我没有看到你的源代码。 – Kissaki 2010-12-10 02:15:13
@Kissaki,不应该`cout 2010-12-10 04:47:54