C/C++ regelnummer

Kan ik omwille van het debuggen het regelnummer in C/C++-compilers krijgen?
(standaardmanier of specifieke manieren voor bepaalde compilers)

bijv.

if(!Logical)
    printf("Not logical value at line number %d \n",LineNumber);
    // How to get LineNumber without writing it by my hand?(dynamic compilation)

Antwoord 1, autoriteit 100%

U moet de preprocessor-macro __LINE__en __FILE__gebruiken. Het zijn voorgedefinieerde macro’s en onderdeel van de C/C++-standaard. Tijdens de voorverwerking worden ze respectievelijk vervangen door een constante tekenreeks met een geheel getal dat het huidige regelnummer vertegenwoordigt, en door de huidige bestandsnaam.

Andere preprocessorvariabelen:

  • __func__: functienaam (dit maakt deel uit van C99, niet alle C++-compilers ondersteunen het)
  • __DATE__: een tekenreeks van de vorm “Mmm dd yyyy”
  • __TIME__: een tekenreeks in de vorm “uu:mm:ss”

Uw code is:

if(!Logical)
  printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);

Antwoord 2, autoriteit 33%

Als onderdeel van de C++-standaard bestaan ​​er enkele vooraf gedefinieerde macro’s die u kunt gebruiken. Paragraaf 16.8 van de C++-standaard definieert onder andere de macro __LINE__.

__LINE__:het regelnummer van de huidige bronregel (een decimaal
constant).
__FILE__:de vermoedelijke naam van het bronbestand (een tekenreeks
letterlijk).
__DATE__:de datum van vertaling van het bronbestand (een tekenreeks
letterlijk…)
__TIME__:het tijdstip van vertaling van het bronbestand (een tekenreeks
letterlijk…)
__STDC__:of__STDC__vooraf is gedefinieerd
__cplusplus:De naam __cpluspluswordt gedefinieerd als de waarde 199711L wanneer
een C++-vertaaleenheid samenstellen

Dus uw code zou zijn:

if(!Logical)
  printf("Not logical value at line number %d \n",__LINE__);

Antwoord 3, autoriteit 9%

Je zou een macro kunnen gebruiken met hetzelfde gedrag als printf(),
behalve dat het ook foutopsporingsinformatie bevat, zoals:
functienaam, klasse en regelnummer:

#include <cstdio>  //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a,  __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)

Deze macro’s zouden zich identiek moeten gedragen als printf(), terwijl ze java stacktrace-achtige informatie bevatten. Hier is een hoofdvoorbeeld:

void exampleMethod() {
    println("printf() syntax: string = %s, int = %d", "foobar", 42);
}
int main(int argc, char** argv) {
    print("Before exampleMethod()...\n");
    exampleMethod();
    println("Success!");
}

Wat resulteert in de volgende uitvoer:

main(main.cpp:11) Voor exampleMethod()…
voorbeeldMethod(main.cpp:7) printf() syntaxis: string = foobar, int = 42
main(main.cpp:13) Succes!


Antwoord 4, autoriteit 5%

Gebruik __LINE__(dat is dubbel onderstrepingsteken LINE dubbel onderstrepingsteken), de preprocessor zal het vervangen door het regelnummer waarop het wordt aangetroffen.


Antwoord 5, autoriteit 5%

C++20 biedt een nieuwe manier om dit te bereiken door gebruik te maken van std::source_location. Dit is momenteel toegankelijk in gcc en klinkt als std::experimental::source_locationmet #include <experimental/source_location>.

Het probleem met macro’s zoals __LINE__is dat als je bijvoorbeeld een logfunctie wilt maken die het huidige regelnummer samen met een bericht uitvoert, je altijd __LINE__als een functieargument, omdat het is uitgevouwen op de aanroepsite.
Zoiets als dit:

void log(const std::string msg) {
    std::cout << __LINE__ << " " << msg << std::endl;
}

Zal altijd de regel van de functiedeclaratie uit en niet de regel waar logfeitelijk vandaan werd aangeroepen.
Aan de andere kant, met std::source_locationkun je zoiets als dit schrijven:

#include <experimental/source_location>
using std::experimental::source_location;
void log(const std::string msg, const source_location loc = source_location::current())
{
    std::cout << loc.line() << " " << msg << std::endl;
}

Hier wordt locgeïnitialiseerd met het regelnummer dat wijst naar de locatie waar logwerd gebeld.
Je kunt het hier online proberen.


Antwoord 6, autoriteit 4%

Afrekenen __FILE__en __LINE__macro’s


Antwoord 7, autoriteit 2%

Voor degenen die het misschien nodig hebben, een “FILE_LINE”-macro om gemakkelijk bestand en regel af te drukken:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)

Antwoord 8, autoriteit 2%

Probeer __FILE__en __LINE__.
Mogelijk vindt u __DATE__en __TIME__ook nuttig.
Maar tenzij u een programma aan de clientzijde moet debuggen en dus deze informatie moet loggen, moet u normale debugging gebruiken.


Antwoord 9

Omdat ik nu ook met dit probleem worstel en ik geen antwoord kan toevoegen op een andere, maar ook geldige vraag hier,
ik zal een voorbeeldoplossing geven voor het probleem van:
alleen het regelnummer krijgen van waar de functie is aangeroepen in C++ met behulp van sjablonen.

Achtergrond: in C++ kan men niet-type integere waarden gebruiken als sjabloonargument. Dit is anders dan het typische gebruik van gegevenstypen als sjabloonargumenten.
Het idee is dus om zulke integere waarden te gebruiken voor een functieaanroep.

#include <iostream>
class Test{
    public:
        template<unsigned int L>
        int test(){
            std::cout << "the function has been called at line number: " << L << std::endl;
            return 0;
        }
        int test(){ return this->test<0>(); }
};
int main(int argc, char **argv){
    Test t;
    t.test();
    t.test<__LINE__>();
    return 0;
}

Uitvoer:

de functie is aangeroepen op regelnummer: 0

de functie is aangeroepen op regelnummer: 16

Eén ding om hier te vermelden is dat het in C++11 Standard mogelijk is om standaard sjabloonwaarden op te geven voor functies die gebruikmaken van sjabloon. In pre-C++11 lijken standaardwaarden voor niet-type-argumenten alleen te werken voor class-template-argumenten. In C++11 zou het dus niet nodig zijn om dubbele functiedefinities te hebben zoals hierboven. In C++11 is het ook geldig om const char* sjabloonargumenten te hebben, maar het is niet mogelijk om ze te gebruiken met letterlijke waarden zoals __FILE__of __func__zoals vermeld hier.

Dus uiteindelijk, als je C++ of C++11 gebruikt, kan dit een heel interessant alternatief zijn dan het gebruik van macro’s om de aanroepende lijn te krijgen.


Antwoord 10

Gebruik __LINE__, maar wat is het type?

LINEHet vermoedelijke regelnummer (binnen het huidige bronbestand) van de huidige bronregel (een geheel getalconstante).

Als een gehele constantekan code vaak aannemen dat de waarde __LINE__ <= INT_MAXis en dus is het type int.

Om in C af te drukken, heeft printf()de overeenkomende specificatie nodig: "%d". Dit is een veel kleinere zorg in C++ met cout.

Pedante zorg:als het regelnummer INT_MAX1overschrijdt (enigszins denkbaar met 16-bits int) , hopelijk zal de compiler een waarschuwing produceren. Voorbeeld:

format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]

Als alternatief kan code bredere typen dwingen om dergelijke waarschuwingen te voorkomen.

printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));

Vermijd printf()

Om alle beperkingen van gehele getallen te vermijden: stringify. Code kan direct worden afgedrukt zonder een printf()-aanroep: een leuk ding om te vermijden bij foutafhandeling2.

#define xstr(a) str(a)
#define str(a) #a
fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);

1Zeker een slechte programmeerpraktijk om zo’n groot bestand te hebben, maar misschien kan de door de machine gegenereerde code hoog worden.

2Bij het debuggen werkt code soms gewoon niet zoals gehoopt. Het aanroepen van complexe functies zoals *printf()kan zelf problemen opleveren versus een simpele fputs().

Other episodes