Hallo
Ich benutze den GNU GCC Compiler für ein Projekt. Dieses Projekt enthält
sehr viele asserts.
Wenn ein assert ausgelöst wird, so wird auf einer Konsole einiges an
Information ausgespuckt. Unter anderem der Name des Files welchen den
assert auslöst, die Zeilennummer sowie der Grund für den assert.
Normalerweise werden bei einem Release die asserts ausgeschaltet, um
Speicherplatz einsparen zu können. Das möchte ich aber aus verschiedenen
Gründen nicht tun.
Also bleibt mir nichts anderes übrig als den assert abzukürzen. Eine
Optimierungsmöglichkeit wäre da das Makro
1
__FILE__
Der Präprozessor des Compilers ersetzt dieses Makro durch den Filenamen.
Also etwas in der Form "/usr/local/include/myheader.h".
Das Makro
1
__FILE__
enthält also gemäss Standard nicht nur den Filenamen, sondern auch den
Pfad, wo sich das File befindet. Das kann ein sehr langer Text sein,
welcher dementsprechend viel Speicher benötigt.
Nun meine Frage:
Kann ich durch irgend eine Option den GCC dazu zwingen das Macro
1
__FILE__
ohne den Pfad zu erzeugen? Dann nämlich hätte ich schon sehr viel an
Speicher eingespart.
Unter folgendem Link habe ich keinen Hinweis darauf gefunden wie das
gemacht werden könnte:
http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
Für einen Tipp oder Hinweis bin ich dankbar.
Gruss
Wym
Da würd ich eher mich in der gcc-help@gcc.gnu.org Mailing-Liste anmelden
und dann dort fragen.
http://gcc.gnu.org/lists.html
Falls es nicht geht — absehbar — dann ist __FILENAME__ vielleicht eine
sinnvolle Erweiterung.
Gibt __FILE__ denn immer den absoluten Pfad? Oder das, was man gcc/cc1
übergibt? In letzerem Falle hilft Umschreiben des
Build-Prozesses/Makefiles.
Vielen Dank für den Hinweis!
Ich habe es ausprobiert, und es liegt am Aufruf des Compilers wie Johann
vermutet und Leo bestätigt hat.
Der Build-Prozess muss umgeschrieben werden.
Wäre zwar wesentlich einfacher ein Macro zur Verfügung zu haben welches
den Pfad nicht enthält, aber leider bin ich diesbezüglich nicht fündig
geworden.
Wenn du den String mit dem Dateinamen als separaten String statt per
Konkatenation verwendest (also nicht so: "Assert 1==2 failed in "
_FILE_ sondern printf-ähnlich "Assert %s failed in %s"), dann sollte
gcc schlau genug sein, den Dateinamen nur einmal im binary abzulegen, da
es ja in diesem Fall immer der selbe string ist. Die Assert-Basismeldung
kann dann nebenbei auch noch geshared werden.
Das hängt natürlich vom verwendeten assert-Mechanismus ab, es lohnt sich
möglicherweise seine eigenen Makros dafür zu schreiben.
Leo C. schrieb:> An gcc bzw. __FILE__ liegt es nicht:
Jein. Der Präprozessor fügt dort den Dateinamen ein, mit dem er
die Datei geöffnet hat. Insbesondere also bei impliziten Include-
Pfaden ist es ein absolter Pfadname.
Ich habe mal im Präprozessor-Code nachgesehen, etwas wie das von
Johann als Idee vorgeschlagene __FILENAME__ gibt's derzeit nicht.
Sollte nicht schwierig sein, das zu implementieren, das größte
Problem ist es sicher, den OS-abhängigen Verzeichnistrenner zu
ermitteln und zu berücksichtigen. (Das ist nicht zwingend nur die
Entscheidung zwischen '/' und '\\', sondern meines Wissens dürfte
auch VMS noch unterstützt sein, welches wohl '.' benutzt.)
Da assert() relativ schlicht ist und schnell geschrieben, wäre es
vielleicht eine Lösung: eigenes assert() bauen, darin aber nicht
_FILE_ ausgeben, sondern stattdessen eine eigene Funktion aufrufen,
die den Namen wie gewünscht beschneidet (ist ja jetzt per Definition
keine Körperverletzung mehr).
Wenn die Originalversion etwa so aussehen könnte (nur gcc wg.
_PRETTY_FUNCTION_):
1
#define assert(a) \
2
if( !(a) ) \
3
{ \
4
fprintf( stderr, \
5
__FILE__":%d:%s Assertion `" #a "\' failed\n", \
6
__LINE__, \
7
__PRETTY_FUNCTION__ \
8
); \
9
abort(); \
10
}
kann man sich selbst ein eigenes assert() so schreiben:
1
inlineconstchar*littleJewischPrince(constchar*s)
2
{
3
constchar*p_slash=strrchr(s,'/');
4
return(p_slash?p_slash+1:s);
5
}
6
7
#define assert(a) \
8
if( !(a) ) \
9
{ \
10
fprintf( stderr, \
11
"%s:%d:%s Assertion `" #a "\' failed\n", \
12
littleJewischPrince(__FILE__), \
13
__LINE__, \
14
__PRETTY_FUNCTION__ \
15
); \
16
abort(); \
17
}
Bei größeren Programmen habe ich früher oder später ohnehin immer
assert() selbst definiert, weil man dann noch andere Spielereien
einbauen kann (aktuellen Stand von irgendwelchen Kellerleichen dumpen
o.ä.).
@Sam: Wir verwenden eCos als Betriebssystem. eCos ist von seiner Idee
her stark modularisiert, was zu sehr tiefen Verzeichnis-Strukturen
führt. Daher auch meine Idee den Pfad zu entfernen, da es sich wirklich
lohnt. Die von Dir vorgeschlagene Optimierung ist wahrscheinlich
innerhalb eines Files wirksam. Ich verspreche mir daher nicht eine
wesentliche Einsparung aufgrund der grossen Verteilung auf (extrem)
viele Files.
Wie ich im Code von eCos feststellen konnte ist der assert zwar nicht
mit printf aufgebaut, aber der Compiler sollte trotzdem bereits jetzt
die von Dir erwähnte Optimierung vornehmen, da alle verschiedenen
asserts letztendlich zentral über einen einzigen Funktionsaufruf
implementiert sind:
Hinzu kommt noch unsere eigene Applikation welche sich in der
Verzeichnis-Struktur an einem anderen Ort befindet (übrigens auch tief
verschachtelt). Darin haben wir die asserts etwas anders formuliert.
Hier verwenden wir am Ende einen printf Mechanismus. Nachdem der assert
in einem Logger festgehalten wurde wird ein hartes reset ausgelöst:
@Klaus: Habe ich das nicht verstanden? Das wird mir doch keinen Code
einsparen? Es wird zwar nur der Filename und nicht der Pfad ausgegeben,
aber im build wird trotzdem der ganze string bestehend aus Pfad und
Filename integriert?
sorry, ich hatte nicht realisiert, daß es dir um die gespeicherten
Strings geht.
Die werden natürlich nicht kleiner, nur die Ausgabe.
Wenn ihr mit make arbeitet, könnte man ersatzweise beim Kompilieren den
nackten Namen ohne Pfad als Makro übergeben und das dann für ein assert
nehmen.
@Klaus: Das ist eine guter Vorschlag. Wenn ich die Problematik als
Ganzes betrachte wird das wohl die beste Lösung sein.
@Jörg: Den GCC ändern wäre wohl eine Möglichkeit, aber das geht mir
persönlich doch etwas zu weit.
Klaus Wachtler schrieb:> sorry, ich hatte nicht realisiert, daß es dir um die gespeicherten> Strings geht.> Die werden natürlich nicht kleiner, nur die Ausgabe.>> Wenn ihr mit make arbeitet, könnte man ersatzweise beim Kompilieren den> nackten Namen ohne Pfad als Makro übergeben und das dann für ein assert> nehmen.
Das wollte ich auch schon vorschlagen. Ddas kann man im Makefile z.B.
direkt über die CFLAGS machen: