Beginnen wir mit einem Beispiel, ich denke, das wird das Problem demonstrieren, mit dem ich mich sofort beschäftige. Dies ist ein einfaches Testprogramm, weit von realistischen, aber es funktioniert sehr gut, das Problem veranschaulichtWie man Valgrind mit einer Funktion verwendet, die eigentlich die Erweiterung eines Makros ist
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 struct first {
5 int i_value;
6 };
7
8 struct second {
9 float f_value;
10 };
11
12 #define DEFINE_FUNCTION(type, struct_name, field_name) \
13 void my_ ## type ## _function(struct struct_name *object, type value) \
14 { \
15 /* Deliberately read an uninitialized value to make valgrind */ \
16 /* report the issue */ \
17 if (object->field_name == -1) \
18 return; \
19 object->field_name = value; \
20 }
21
22 DEFINE_FUNCTION(int, first, i_value);
23 DEFINE_FUNCTION(float, second, f_value);
24
25 void
26 my_test_function(struct first *object, int value)
27 {
28 /* Deliberately read an uninitialized value to make valgrind */
29 /* report the issue */
30 if (object->i_value == -1)
31 return;
32 object->i_value = value;
33 }
34
35 int
36 main(void)
37 {
38 struct first frst;
39 struct second scnd;
40
41 my_test_function(&frst, -5);
42 my_int_function(&frst, -2);
43 my_float_function(&scnd, 3.0);
44
45 return 0;
46 }
Wenn Sie diesen Code kompilieren und
valgrind --show-origins=yes ./compiled-program
verwenden Sie ein ouput wie
==25304== Memcheck, a memory error detector
==25304== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==25304== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==25304== Command: ./macro-valgrind
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x40056F: my_test_function (macro-valgrind.c:30)
==25304== by 0x400597: main (macro-valgrind.c:41)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x40053A: my_float_function (macro-valgrind.c:23)
==25304== by 0x4005BC: main (macro-valgrind.c:43)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x400547: my_float_function (macro-valgrind.c:23)
==25304== by 0x4005BC: main (macro-valgrind.c:43)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304==
==25304== HEAP SUMMARY:
==25304== in use at exit: 0 bytes in 0 blocks
==25304== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==25304==
==25304== All heap blocks were freed -- no leaks are possible
==25304==
==25304== For counts of detected and suppressed errors, rerun with: -v
==25304== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
sehen
Wie Sie in der obigen Valgrind-Ausgabe sehen können, stammt der erste nicht initialisierte Lesevorgang von der my_test_function()
-Funktion und zeigt die genaue Zeile whe an Das Problem ist aufgetreten. Auf diese Weise ist es ziemlich einfach, den Code zu reparieren. Die anderen Berichte sind offensichtlich nicht zu verstehen. Das Beste, was Sie damit tun können, ist zu wissen, welche Funktion es war, aber das ist alles.
Ich verstehe, dass der generierte Code verwirrend valgrind ist und deshalb meine eigentliche Frage ist,
- Gibt es eine Möglichkeit, den Code mit gcc zu kompilieren, die diese Art von Funktionen valgrind verstehen helfen kann?
Beenden Sie die Verwendung von Makros und vertrauen Sie dem Compiler zum Inline-Schreiben? Hand-erweitern in den wichtigen Fällen, nur um die Daten zu bekommen, die Sie brauchen? Microbenchmark nur der Mut des Makros? – bmargulies
@bmargulies Das Makro emuliert C++ - Vorlagen. Es hat nichts mit Leistung zu tun. – user3386109