2016-07-24 6 views
4

例を挙げて説明しますが、これは私が直面している問題を実証すると思います。これは、現実的にはほど遠い、簡単なテストプログラムであるが、それはあなたが 実際にマクロを展開する関数でvalgrindを使用する方法

==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) 
のような出力に含まが表示されます。このコードをコンパイルして

valgrind --show-origins=yes ./compiled-program 

を使用する場合、問題は非常によく

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 } 

を示してい

上記のvalgrind出力からわかるように、最初に読み込まれた初期化されていない読み取りはmy_test_function()関数からのもので、問題が発生しました。このようにすれば、コードを修正するのはかなり簡単です。他のレポートは明らかに理解することが不可能です。あなたが彼らとできることは、それがどの機能であったかを知ることですが、それだけです。

は私が

  • はvalgrindのを助ける機能のこの種を理解することができgccでコードをコンパイルする方法はあります、生成されたコードが混乱valgrindで、私の実際の質問は、なぜそれがだと理解できますか?
+0

停止のマクロを使用してインライン化するコンパイラを信頼?必要なデータを取得するだけで、重要な場合は手動で展開します。マイクロベンチマークはマクロの邪魔になりませんか? – bmargulies

+1

@bmarguliesマクロはC++テンプレートをエミュレートします。それはパフォーマンスとは関係ありません。 – user3386109

答えて

3

あなたが探している機能が存在する可能性は低いと思います。理由を理解するには、これにコードを変更:

#define DEFINE_FUNCTION(type, struct_name, field_name)    \ 
void my_ ## type ## _function(struct struct_name *object, type value) \ 
{                  \ 
    printf("%s %d\n", # type, __LINE__); \ 
    printf("%s %d\n", # type, __LINE__); \ 
} 

DEFINE_FUNCTION(int, first, i_value); 
DEFINE_FUNCTION(float, second, f_value); 

void my_test_function(struct first *object, int value) 
{ 
    printf("test %d\n", __LINE__); 
    printf("test %d\n", __LINE__); 
} 

出力は

test 24 
test 25 
int 19 
int 19 
float 20 
float 20 

ポイントは、あなたがこのようにそれを書いたかのように、コンパイラは、コードを一行としてmy_int_functionを見ているということであるだろう

void my_int_function(struct struct_name *object, type value) { printf("%s %d\n", "int", __LINE__); printf("%s %d\n", "int", __LINE__); } 

コードの一行に複数行のマクロの変換は、あなたの関数であり、コンパイラは行番号を割り当てる程度取得時間によってように、プリプロセッサによって行われますすでに1行のコードです。

実際には、-Eでコンパイルして、プリプロセッサの動作を確認できます。

参考のために、セクション5.1.1.2翻訳フェーズをC11ドラフト仕様で参照してください。

翻訳の構文規則の優先順位は、 によって次のように指定されています。 必要に応じ6)

  1. 物理ソースファイルのマルチバイト文字は、ソース文字に、実装に定義されたように、マッピングされている()は、エンド・オブ・ライン指標の改行文字を導入 を設定します。トリグラフシーケンスは、対応する 1文字の内部表現に置き換えられます。

  2. 直ちに改行文字が続くバックスラッシュ文字()の各インスタンスは フォーム論理ソース線に、スプライシング物理ソース行を削除します。これらの別個の相が発生した場合のように[...]

6)の実装は、多くは、典型的には、実際に一緒に折り畳まれているにもかかわらず、 に動作しなければなりません。 [...]

+1

は、私は 'GCCの-E'を実行するために私には発生しなかった理由は分からない、と私はプリプロセッサが責任だと思っていなかったことを推測するが、それは責任があります。 –

5

私は、マクロ誘発デバッグ問題のこのスタイルを解決:gccの通過-E -C/

1 /標準ライブラリ/サードパーティーの#includeをコメントアウト

3 /非常に長い行を/

4バックの#includeを入れ壊す打ち鳴らす形式、通過するマクロを展開-P、

5 /デバッグ情報でコンパイル

プログラムは以前と同じですが、gdbとvalgrindは展開されたソースを参照しています。その後、バグを見つけて、diffツールを使用して元のソースに戻すことは比較的簡単です。

疼痛など上記音が、1〜4のステップは、ステップ5と同じようにスクリプトであるため、開発中の実際のオーバーヘッドは最小です。これが私のデフォルトではない理由は、ideでのエラーへのジャンプが、生成されたコードへと私を連れて行くことです。

+0

これは本当に多くの問題です。おそらく、コードが間違っている理由を理解することで、バグを見つけやすくなります。 –

+0

初めての書き込みは面倒でしたが、今は別のビルドターゲットです。 '拡大する'。マクロのやり取りにも役立ちます。 –

関連する問題