Czy ze względu na debugowanie mogę uzyskać numer wiersza w kompilatorach C / C ++? (sposób standardowy lub specyficzny dla niektórych kompilatorów)
na przykład
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
Odpowiedzi:
Należy użyć makra preprocesora
__LINE__
i__FILE__
. Są to predefiniowane makra i część standardu C / C ++. Podczas przetwarzania wstępnego są one zastępowane odpowiednio stałym łańcuchem zawierającym liczbę całkowitą reprezentującą numer bieżącego wiersza i bieżącą nazwę pliku.Inne zmienne preprocesora:
__func__
: nazwa funkcji (jest to część C99 , nie wszystkie kompilatory C ++ ją obsługują)__DATE__
: ciąg w postaci „Mmm dd yyyy”__TIME__
: ciąg w postaci „hh: mm: ss”Twój kod będzie:
źródło
#define S1(N) #N
#define S2(N) S1(N)
#define LINESTR S2(__LINE__)
. Zobacz c-faq.com/ansi/stringize.html__func__
nie jest makrem, to niejawnie zadeklarowana zmienna.W ramach standardu C ++ istnieje kilka wstępnie zdefiniowanych makr, których można użyć. Sekcja 16.8 standardu C ++ definiuje między innymi
__LINE__
makro.Twój kod wyglądałby więc tak:
źródło
Możesz użyć makra zachowującego się tak samo jak printf () , z tą różnicą, że zawiera również informacje debugowania, takie jak nazwa funkcji, klasa i numer wiersza:
Te makra powinny zachowywać się identycznie jak printf () , jednocześnie włączając informacje podobne do java stacktrace. Oto przykład główny:
Co daje następujący wynik:
źródło
#include
na<stdio.h>
Użyj
__LINE__
(to jest podwójne podkreślenie Podwójne podkreślenie LINE), preprocesor zastąpi go numerem linii, w której jest napotkany.źródło
Zamówienie
__FILE__
i__LINE__
makraźródło
C ++ 20 oferuje nowy sposób osiągnięcia tego za pomocą std :: source_location . Jest to obecnie dostępne w gcc an clang jak w
std::experimental::source_location
przypadku#include <experimental/source_location>
.Problem z takimi makrami
__LINE__
polega na tym, że jeśli chcesz utworzyć na przykład funkcję rejestrującą, która wyświetla bieżący numer linii wraz z komunikatem, zawsze musisz przekazać__LINE__
jako argument funkcji, ponieważ jest on rozwijany w miejscu wywołania. Coś takiego:Zawsze wyświetla wiersz deklaracji funkcji, a nie wiersz, z którego
log
została wywołana. Z drugiej stronystd::source_location
możesz napisać coś takiego:Tutaj
loc
jest inicjalizowany numerem linii wskazującym na lokalizację, w którejlog
został wywołany. Możesz spróbować online tutaj.źródło
Spróbuj
__FILE__
i__LINE__
.Możesz również znaleźć
__DATE__
i__TIME__
przydatne.Chociaż jeśli nie musisz debugować programu po stronie klienta, a tym samym musisz rejestrować te informacje, powinieneś użyć normalnego debugowania.
źródło
raw code
(w ten sposób: `__`). @mmyers próbował pomóc, ale uniknął tylko jednego z podkreśleń, więc pozostała ci składnia znaczników dla kursywy . Jednak głosy przeciwne są tutaj nieco szorstkie, zgadzam się.Dla tych, którzy mogą tego potrzebować, makro „FILE_LINE” do łatwego drukowania pliku i wiersza:
źródło
Ponieważ teraz stawiam czoła temu problemowi i nie mogę dodać odpowiedzi na inne, ale również ważne pytanie zadane tutaj , podam przykładowe rozwiązanie problemu: uzyskanie tylko numeru wiersza, w którym funkcja została wywołana C ++ przy użyciu szablonów.
Tło: w C ++ można użyć wartości całkowitych innych niż typ jako argumentu szablonu. Różni się to od typowego użycia typów danych jako argumentów szablonu. Chodzi więc o to, aby użyć takich wartości całkowitych dla wywołania funkcji.
Wynik:
Należy tu wspomnieć, że w C ++ 11 Standard można podać domyślne wartości szablonu dla funkcji korzystających z szablonu. W pre C ++ 11 domyślne wartości argumentów innych niż typowe wydają się działać tylko dla argumentów szablonu klasy. Zatem w C ++ 11 nie byłoby potrzeby stosowania zduplikowanych definicji funkcji, jak powyżej. W C ++ 11 można również mieć argumenty szablonu const char *, ale nie można ich używać z literałami takimi jak
__FILE__
lub__func__
jak wspomniano tutaj .Więc w końcu, jeśli używasz C ++ lub C ++ 11, może to być bardzo interesująca alternatywa niż używanie makr do uzyskania linii wywołującej.
źródło
Użyj
__LINE__
, ale jaki jest jego typ?Jako stała liczba całkowita kod często przyjmuje wartość,
__LINE__ <= INT_MAX
a więc typ jestint
.Aby drukować w C,
printf()
potrzebuje specyfikator dopasowanie:"%d"
. Jest to znacznie mniejszy problem w C ++ zcout
.Pedantyczna obawa: jeśli numer linii przekroczy
INT_MAX
1 (nieco wyobrażalne w przypadku wersji 16-bitowejint
), miejmy nadzieję, że kompilator wyświetli ostrzeżenie. Przykład:Alternatywnie, kod mógłby zmusić szersze typy do uprzedzania takich ostrzeżeń.
Uniknąć
printf()
Aby uniknąć wszystkich ograniczeń liczb całkowitych: stringify . Kod może być drukowany bezpośrednio bez
printf()
wywołania: miła rzecz, której należy unikać w obsłudze błędów 2 .1 Z pewnością kiepska praktyka programistyczna przy tak dużym pliku, ale być może kod generowany maszynowo może być wysoki.
2 Podczas debugowania czasami kod po prostu nie działa zgodnie z oczekiwaniami. Wywoływanie złożonych funkcji, takich jak
*printf()
samo w sobie, może powodować problemy, a nie prostefputs()
.źródło