2015-03-11 34 views
8

Zajmuję się tworzeniem niektórych modułów dla systemu automatyzacji napisanego w języku C i muszę wykonać wiele pracy ze sprzętem. I nie widzę prostego sposobu (jak tradycyjne) do debugowania rzeczy zamiast dzienników śledzenia. Tak więc szukam dobrej praktyki do rejestrowania wywołań funkcji. Co najmniej sekwencja wywołań i wartości zwracanych.Śledzenie wywołań funkcji w C

Sposób, w jaki odbywa się w aplikacji jest bardzo prosta i właściwie zanieczyszcza kod z konstrukcji nieistotnych jak

int function (int param){ 
    if(trace_level & LOG_FCALLS){ 
     writelog("Entering function()"); 
    } 

    /* something useful */ 

    if(trace_level & LOG_FCALLS){ 
     writelog("Exit from function()=%d", ret); 
    } 
} 

postanowiłem wykorzystać makro, które zrobi całą brudną robotę. Teraz wygląda to tak

#define LOG_E(fn) const char *__fname=fn; printf("LOG: Entry to %s\n",__fname) 
#define return(ret)  printf("LOG: Exit from %s()=%d\n",__fname,ret) 

int testFunc(){ 
    LOG_E("testFunc"); 

    /*do useful things */ 

    return(ret); 
} 

widzę problemów z tym kodem

  1. mam nadrzędne return, a to wymaga, aby napisać return(ret) cały czas zamiast return ret. Łatwo jest zapomnieć o tym problemie.

  2. Definiuję zmienną łańcuchową w moim makrze. Jestem świadomy, że makro istnieje w C99, ale mój kompilator niestety nie obsługuje tego makra ani żadnych innych istotnych makr.

  3. Jak rejestrować wartości argumentów funkcji?

Jestem pewien, że to nie jest nowy problem i nie jestem pierwszym, który stanął przed tym. Jestem również świadomy rzeczy AOP, ale oprzyrządowanie kodu jest niedopuszczalne rozwiązanie dla mojego systemu i nie znalazłem żadnej możliwości, aby to zrobić z moim kompilatorem.

Poszukuję więc dobrych pomysłów, jak zaimplementować śledzenie w najbardziej elegancki sposób.

Moja okolica: kod Legacy, C, Watcom 10.x, OS czasu rzeczywistego

+1

Co z tego, że w rzeczywistości nie wróci w ogóle? tzn. twój 'return (ret)' jest zjedzony przez makro i zamieniony na 'printf', a następnie funkcja nie ma instrukcji return do wykonania. Nie powracasz w tym makrze. – ArjunShankar

+1

Watcom C obsługuje makro '__FUNCTION__'. – Matt

+1

Na wypadek gdybyś przetestował istnienie '__func__' przez' # ifdef': To nie jest makro, ale statyczna tablica (jak gdyby została zadeklarowana z 'static cosnt char __func __ [] =" ... "; 'na początku funkcji). – mafso

Odpowiedz

1
#if defined(DEBUG_BUILD) 
# define START_FUNCTION if(trace_level & LOG_FCALLS){writelog("+++ %s()", __func__) 
    } 
# define END_FUNCTION if(trace_level & LOG_FCALLS){writelog("--- %s()", __func__) 
#elif defined (TIMING_BUILD) 
# define START_FUNCTION WRITE_TIMED_LOG("+++") 
# define END_FUNCTION WRITE_TIMED_LOG("---") 
#else 
# define START_FUNCTION 
# define END_FUNCTION 
#endif 
int function (int param){ 
    START_FUNCTION; 
    ... 
    if(error_occurred) { 
    END_FUNCTION; 
    return errror_code; 
    } 
    ... 
    END_FUNCTION; 
    return 42; 
} 
+0

wygląda mi jak opcja. Ponieważ nie chcę łamać słowa kluczowego return. Ale niepokojące jest to, że przed każdym zwrotem musimy napisać 'END_FUNCTION'. – evrdrkgrn0

5

super-poważny, profesjonalny sposób, aby to zrobić jest stworzenie odrębnego projektu debug/test, który jest całkowicie oddzielony od kodu produkcyjnego. To jest tak:

  • Upewnij się, że masz kopię zapasową/zatwierdzenie na kodzie produkcyjnym.
  • Wykonaj wydruk w postaci kodu produkcyjnego na dysku twardym. To stanie się twoim testowym projektem.
  • Utwórz plik dziennika .txt gdzie piszesz pełny podpis każdej funkcji, którą chcesz się zalogować, na przykład:

    int function (int param) 
    float function2 (void) 
    ... 
    
  • Tworzenie trochę PC program/skrypt, który zaczyna powyższy plik .txt jako wejście , następnie przeszukuje kod źródłowy pod kątem pasujących linii definicji funkcji. Program komputerowy wygeneruje nowy plik .c oparty na oryginalnym kodzie, w którym wstawi kod rejestrowania debugowania do żądanych funkcji, po { i przed. Przygotowanie takiego programu zajmie kilka godzin.
  • Połącz swój projekt testowy, używając zmodyfikowanego kodu źródłowego utworzonego przez skrypt.

Powyższa metoda polega na tym, jak sam to robię w przypadku oprogramowania o znaczeniu krytycznym, w którym obowiązują wymagania norm bezpieczeństwa (MISRA, zasięg kodu itp.), Zgodnie z którymi nie można wprowadzać kodu, który nie jest wykonywany w produkcie końcowym.

Ta metoda zapewnia integralność kodu produkcyjnego i gwarantuje, że żadne błędy nie zostały dodane do programu przez kod test/debugowanie. Pozostawia również bałagan kompilacji przełączników itp. Z kodu produkcyjnego. I nie będziesz miał żadnego starego kodu debugowania w twoim projekcie, którego zapomniałeś usunąć (inaczej I zawsze zapomniałem jakiegoś fragmentu kodu debugowania gdzieś w moich programach).

+0

> wersja papierowa kodu produkcyjnego <. Łał! Czy próbowałeś SCM takich jak SVN, Git, Mercurial? – myaut

+0

@myaut Dlatego właśnie powiedziałem "upewnij się, że masz kopię zapasową/_commit_". Zatwierdzenie to wersja papierowa. – Lundin

+0

To świetny przykład automatyzacji, wezmę notatkę. Może to być również przypadek, gdy potrzebujemy dziennika śledzenia z systemu produkcyjnego. Na przykład w przypadku błędów, które można odtworzyć w rzeczywistym środowisku. – evrdrkgrn0

0

To działa w MS Visual C. Potrzebne będą różne wersje makra return dla różnych typów danych (lub bez).

#include <stdio.h> 

#define TRACING 

#ifdef TRACING 
#define LOG_E printf("Func: %s\n", __FUNCTION__); 
#define LOG_R printf("Exit: %s\n", __FUNCTION__); 
#define LOG_I(ival) printf("Exit: %s %d\n", __FUNCTION__, ival); 

#else 
#define LOG_E 
#define LOG_R 
#define LOG_I(ival) 
#endif 

int main(void){ 
    int retval = 0; 
    LOG_E 
    printf("Hello world!\n"); 
    LOG_I(retval) 
    return retval; 

} 

wyjściowa:

Func: main 
Hello world! 
Exit: main 0 
0

Można dostosować kompilator poradzić. Możesz użyć MELT (aby dostosować kompilator gcc), jeśli kompilujesz z GCC.

Może można dostosować openwatcom (lub zapłacić pewną OpenWatcom eksperta to zrobić) ...

Powiązane problemy