c ++ - Uventet Non-NULL returnering

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg spiller med TagLib (på Windows, bygget med MingW). Jeg forsøger at få TagLib til at genkende, når der ikke findes ID3v1 eller ID3v2 information i en MP3-fil. Ifølge TagLib-dokumentationen skal funktionen ID3v2Tag () i et MPEG-filobjekt returnere en NULL-pointer, når der ikke er nogen ID3v2-information i filen. [14]


Desværre forekommer dette ikke. Jeg har nogle test MP3-filer, jeg har lavet, som jeg bruger i min kode (jeg har stillet filerne til rådighed):



  • blank.mp3 (download), ingen ID3v1 eller ID3v2 oplysninger overhovedet. Jeg kan bekræfte dette ved at lave en almindelig tekst søgning efter 'TAG' og 'ID3' i filerne binære indhold.

  • only\_album\_id3v2.mp3 (download), har ID3v2 information (kun albummet er indstillet)

  • only\_album\_id3v1.mp3 (download), har ID3v1 information (kun albummet er indstillet)



Her er min kode. [15] [16] [17]


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


Kørsel af dette program skal gå i stykker på grund af en NULL-pointerfejl på cout << at->album() << endl;, men det kører helt fint. Også, når jeg cout << ct << endl;, returnerer den en hukommelsesadresse.


Her er output:



  Prøve.

  
  test album id3v2

  
  Programmet er færdigt.



EDIT:
Her er en ny test.


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


Og her er output.



  Test.

  på er ikke NULL.

  bt er ikke NULL.

  ct er ikke NULL.

  Programmet er færdigt.


Bedste reference


Jeg undersøgte TagLibs kode kort.


Jeg ved ikke noget om det og har aldrig brugt det, men koden ser buggy til mig. Her er hvorfor -


I MPEG :: Fil :: læs (), vi leder efter et tag - d->ID3v2Location = findID3v2();. Hvis den ikke eksisterer, tilføjes den ikke til tagsvektoren. Dette er checken - if(d->ID3v2Location >= 0).


Men ved afslutningen af ​​funktionen, lige før vi vender tilbage, har vi -


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


Nu, Id3v2Tag(create) med en ægte parameter, ringer faktisk return d->tag.access(ID3v2Index, create);. Funktionen adgang () er -


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


Så når create er sandt, skaber vi et helt nyt, tomt tag og placerer det i vektoren (ved hjælp af funktionen set().


Det betyder, at uanset om filen indeholder koderne eller ej, tilføjes de til vektoren. Dette er ikke den dokumenterede opførsel. Ligner en fejl.


Jeg ved ikke, hvorfor disse to linjer er nødvendige der - kigge på filens historie kan antydes, hvorfor de blev tilføjet, men det gjorde jeg ikke.


Anyway, jeg vil gerne understrege, at jeg aldrig faktisk udført denne kode. Dette er baseret på rent statisk læsning, kun meget små dele uden at være opmærksom på store problemer.


Jeg tror, ​​at det ikke kan skade, at der åbnes en fejlrapport.

Andre referencer 1


Ved hjælp af en nullpeger resulterer det ikke nødvendigvis i en fejl, du kan se; den er udefineret adfærd. Det ser ud til at virke, eller det kan gøre noget rigtig underligt.


I dette tilfælde genererer compileren sandsynligvis et opkald til TagLib :: ID3v2 :: Tag :: album med dette pegersæt til null, men selv dette er ikke garanteret. Hvad der sker inde i funktionen er, at nogen er gætte.


Hvis funktionen kan returnere NULL, skal du eksplicit kontrollere det og gøre noget anderledes.

Andre referencer 2


Taglib opretter en 'Tom' ID3v2Tag og ID3v1Tag i objektet, hvis filen ikke har en.

Andre referencer 3


Jeg har et simmilar problem og forhåbentlig har jeg fundet en løsning for ID3v1/ID3v2 tilstedeværelseskontrol.


Det er metode virtual bool TagLib::Tag::isEmpty() const [18]