C / C ++行番号


110

デバッグのために、C / C ++コンパイラで行番号を取得できますか?(特定のコンパイラの標準的な方法または特定の方法)

例えば

if(!Logical)
    printf("Not logical value at line number %d \n",LineNumber);
    // How to get LineNumber without writing it by my hand?(dynamic compilation)

17
@ルーカス:デバッガをいじらないほうがいい人もいます。この種の「貧しい人の断言」は、コードの恒久的な部分であり、計算の状態について真実であるはずの事柄の永続的なドキュメントであるため、より明確になる場合があります。
S.Lott

13
@Lucas:デバッガは、実行時間の長いプログラムで断続的に発生する問題や、クライアントサイトに展開されたソフトウェアの問題に関する情報を収集する場合にも役立ちません。これらの場合、唯一のオプションは、後で分析するために、プログラムがプログラムの状態に関するできるだけ多くの情報をログに記録することです。
KeithB、

1
@Lucasおよびデバッガーは、一部の組み込みシステムではこの情報を取得するためにうまく機能しません。
ジョージストッカー

回答:


180

プリプロセッサマクロ__LINE__とを使用する必要があり__FILE__ます。これらは事前定義されたマクロであり、C / C ++標準の一部です。前処理中に、現在の行番号を表す整数を保持する定数文字列と現在のファイル名にそれぞれ置き換えられます。

その他のプリプロセッサ変数:

  • __func__:関数名(これはC99の一部であり、すべてのC ++コンパイラがそれをサポートしているわけではありません)
  • __DATE__ :「Mmm dd yyyy」形式の文字列
  • __TIME__ :「hh:mm:ss」形式の文字列

あなたのコードは次のようになります:

if(!Logical)
  printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);

2
C99は__FUNCTION__ではなく__func__を使用します。これはAFAIKが部分的に非推奨となっているためです。__func__はCの定数文字列連結には使用できないため、違いがコードを破壊する可能性があります。
ジョセフクインジー

1
GCCマニュアルからの参照:「__FUNCTION__と__PRETTY_FUNCTION__は文字列リテラルとして扱われました。これらはchar配列を初期化するために使用でき、他の文字列リテラルと連結できました。GCC3.4以降では__func__のような変数として扱います。C++では、__ FUNCTION__および__PRETTY_FUNCTION__は常に変数でした。」
ジョセフクインジー2010年

ファイル名と同じように、行番号を文字列として取得する方法はありますか?プリプロセッサに、たとえば整数22ではなく文字列リテラル "22"を与えてほしい
sep332

1
@ sep332はい、ただしcppは奇妙な獣です。そのため、マクロ引数を使用して2つのステップで実行する必要があります。#define S1(N) #N #define S2(N) S1(N) #define LINESTR S2(__LINE__)c-faq.com/ansi/stringize.htmlを
Rasmus Kaj

1
厳密に言うと、これ__func__はマクロではなく、暗黙的に宣言された変数です。
HolyBlackCat 2017年

64

C ++標準の一部として、使用できる定義済みマクロがいくつか存在します。C ++標準のセクション16.8は、特に__LINE__マクロを定義しています。

__LINE__現在のソース行の行番号(10進定数)。
__FILE__ソースファイルの推定名(文字列リテラル)。
__DATE__ソースファイルの翻訳日(文字列リテラル...)
__TIME__ソースファイルの翻訳時間(文字列リテラル...)
__STDC____STDC__事前定義されているかどうか
__cplusplus名前__cplusplusは、値199711Lに定義されている場合C ++翻訳単位のコンパイル

したがって、コードは次のようになります。

if(!Logical)
  printf("Not logical value at line number %d \n",__LINE__);

19

関数名、クラス、行番号などのデバッグ情報も含まれていることを除いて、printf()と同じ動作のマクロを使用できます。

#include <cstdio>  //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a,  __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)

これらのマクロは、javaスタックトレースのような情報を含みながら、printf()と同じように動作する必要があります。ここにメインの例があります:

void exampleMethod() {
    println("printf() syntax: string = %s, int = %d", "foobar", 42);
}

int main(int argc, char** argv) {
    print("Before exampleMethod()...\n");
    exampleMethod();
    println("Success!");
}

これにより、次の出力が得られます。

main(main.cpp:11)exampleMethod()の前...
exampleMethod(main.cpp:7)printf()構文:string = foobar、int = 42
main(main.cpp:13)成功しました!


C開発のために、あなたは変わるだろう#include<stdio.h>
phyatt

11

使用__LINE__(二重下線LINEダブルアンダースコアだ)、プリプロセッサは、それが検出された行番号で置き換えます。



5

C ++ 20は、std :: source_locationを使用してこれを実現する新しい方法を提供します。これは、gccを打ち鳴らすには現在アクセス可能であるstd::experimental::source_location#include <experimental/source_location>

などのマクロの問題__LINE__は、たとえば現在の行番号をメッセージとともに出力するロギング関数を作成する場合__LINE__、呼び出しサイトで展開されるため、常に関数の引数として渡す必要があることです。このようなもの:

void log(const std::string msg) {
    std::cout << __LINE__ << " " << msg << std::endl;
}

関数宣言の行を常に出力し、log実際に呼び出された行は出力しません。一方、std::source_location次のように書くことができます:

#include <experimental/source_location>
using std::experimental::source_location;

void log(const std::string msg, const source_location loc = source_location::current())
{
    std::cout << loc.line() << " " << msg << std::endl;
}

ここでlocは、logが呼び出された場所を指す行番号で初期化されます。 ここでオンラインで試すことができます。


4

試してみてください__FILE____LINE__
あなたも見つけ__DATE____TIME__便利かもしれません。
ただし、クライアント側でプログラムをデバッグする必要がなく、これらの情報をログに記録する必要がない限り、通常のデバッグを使用する必要があります。


なぜ私はこれに反対票を投じたのか、なぜmmyersは私の投稿を編集したのですか?
Sanctus2099 2010年

@ Sanctus2099:Markdownがファイルと行を太字フォントで表示するように二重下線を変換したため、編集されました(答えがどのように表示されるかを確認しないでください)。別のポイントは、(少なくとも今のところ、私にはこのように見えます)既に正しい答えが与えられてから1時間後に答えを出したため、値を追加しなかった可能性があります。
Felix Kling、

二重下線は、太字のマークアップ構文です。二重下線を適切に表示するには、それらをエスケープするか(このように:\ _ \ _)、またはバックraw codeティックを使用してそれらにマークを付ける必要があります(このように: `__`)。@mmyersが助けようとしたが、彼はアンダースコアの1つだけをエスケープしたため、イタリックのマークアップ構文が残った。ここで反対投票は少し厳しいですが、私は同意します。
マットB.

わかりました。ダブルアンダースコアがテキストを太字に変換することに気づかなかったので、行かなければならず、答えがどのようになっているかを確認する時間がありませんでした。わかりました。私の答えが1時間遅れたとしても、それは良い答えでした。何の価値もありませんでしたが、それも間違っていなかったので、反対票を投じる理由はありませんでした。それがあなたが助けようとすることで得られるものです...
Sanctus2099

2
@ Sanctus2099一部の人々はすぐに反対票を投じます。そのため、あなたの答えが正しいことを確認することが重要です。この場合、間違った回答を投稿し、編集せずに4時間放置しました。あなたは自分を責める人が誰もいない。
貧弱

1

私もこの問題に直面していてここで尋ねられた別の有効な質問への回答を追加できないため、問題の解決策の例を提供します:関数が呼び出された場所の行番号のみを取得しますテンプレートを使用したC ++。

背景:C ++では、型のない整数値をテンプレート引数として使用できます。これは、テンプレート引数としてのデータ型の一般的な使用法とは異なります。したがって、そのような整数値を関数呼び出しに使用するという考えです。

#include <iostream>

class Test{
    public:
        template<unsigned int L>
        int test(){
            std::cout << "the function has been called at line number: " << L << std::endl;
            return 0;
        }
        int test(){ return this->test<0>(); }
};

int main(int argc, char **argv){
    Test t;
    t.test();
    t.test<__LINE__>();
    return 0;
}

出力:

関数が行番号0で呼び出されました

関数が行番号16で呼び出されました

ここで言及すべきことの1つは、C ++ 11標準では、テンプレートを使用して関数にデフォルトのテンプレート値を指定できることです。C ++ 11より前のバージョンでは、非型引数のデフォルト値は、クラステンプレート引数に対してのみ機能するようです。したがって、C ++ 11では、上記のように重複する関数定義を持つ必要はありません。C ++ 11ではそのようなリテラルでそれらを使用するのconstのchar *テンプレート引数が、そのことはできないにしても有効__FILE__または__func__言及したように、ここを

したがって、最終的には、C ++またはC ++ 11を使用している場合、これはマクロを使用して呼び出し行を取得するよりも非常に興味深い代替手段になる可能性があります。


1

を使用しますが__LINE__、そのタイプは何ですか?

LINE現在のソース行(整数定数)の(現在のソースファイル内の)推定行番号。

整数定数として、コードは値が__LINE__ <= INT_MAXそうであると仮定することができるので、型は intです。

Cで印刷するにprintf()は、一致する指定子が必要です"%d"。これは、C ++でを使用すると、はるかに問題が少なくなりcoutます。

悩みの種:行番号がINT_MAX1を超える場合(16ビットである程度考えられるint)、コンパイラーが警告を生成することを期待します。例:

format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]

あるいは、コードはより広い型にそのような警告を未然に防ぐように強制することができます。

printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));

避ける printf()

すべての整数制限を回避するには:stringify。コードは、printf()呼び出しなしで直接印刷できます。エラー処理2で回避することをお勧めします。

#define xstr(a) str(a)
#define str(a) #a

fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);

1このような大きなファイルを作成するプログラミングの実践は確かに不十分ですが、おそらく機械で生成されたコードは高くなる可能性があります。

2デバッグでは、コードが期待どおりに機能しないことがあります。のような複雑な関数を呼び出すと*printf()、単純な関数と比較して、それ自体で問題が発生する可能性がありますfputs()


1

それを必要とするかもしれない人のために、ファイルと行を簡単に印刷するための「FILE_LINE」マクロ:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.