LoginSignup
10
2

More than 3 years have passed since last update.

開発時やデバッグの時だけログを出力するさえないやり方

Last updated at Posted at 2019-12-16

はじめに

これは Delphi Advent Calendar 2019 の 17 日目の記事です。

2019/12/17訂正

コメントで指摘されているとおり、インライン関数として定義することで、デバッグビルドのときだけログ出力が実現できるとのことです。

現存するオンラインドキュメントを眺めたところ、少なくともDelphi 2010以降は、確実にサポートしている模様です(see: プロシージャと関数の呼び出し)

残念ですがDelphi7はインライン関数をサポートしていないので、それ以前のバージョンで頑張っている方は諦めましょう。

ほんへ

デバッグ時だけにログ出力して、リリースでは出したくない場合、たいていは

{$IFDEF DEBUG}
OutputDebugString('Hoge');
{$ENDIF}

な事をすると思う。

けどIFDEFENDIFが仰々しくてなんか嫌。

なら、「関数化すればいいじゃない」ということで、コードとしてはこんな感じか。

procedure OutputDebugOnlyString(M: string);
begin
{$IFDEF DEBUG}
OutputDebugString('Hoge');
{$ENDIF}
end;

// .....

begin
  OutputDebugOnlyString('Uge');
end;

けどこの関数、ログ出力の有無にかかわらず、引数は評価されて渡されてしまう。
引数に渡す関数の実行が重い場合、リリース版なのに無駄に処理を食うのなんか嫌(2回目)

そんなわけで、いい方法はないかなと思案した結果がこちら

program DevTimeOnlyLog;

{$APPTYPE CONSOLE}

{$R *.res}

{$IFDEF DEBUG}
  {$C+}
{$ELSE}
  {$C-}
{$ENDIF}

uses
  System.SysUtils,
  Windows;

function TryOutputDebugString(Msg: string): boolean;
begin
  OutputDebugString(PWideChar(Msg));

  Exit(true);
end;

function HeavyFunc(M: string): string;
begin
  OutputDebugString('Begin sleep 2000 ms');

  Sleep(2000);

  OutputDebugString('Complete sleep 2000 ms');

  Result := M;
end;

begin
  try
    Assert(TryOutputDebugString(HeavyFunc('Some Message')));

    Writeln('Press ANY Key');
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

ポイントは、ログ出力をAssert手続きでくくり、コンパイラ指令($C)でログ出力の有無を切り替えるという残念な方法。
ここでは、説明のためコードで直接コンパイラ指令を指定してますが、通常はプロジェクトオプションで。

リリース版では、ログ出力のコードすら生成されなくなって心の平穏を取り戻しましたとさ。ちゃんちゃん。

おまけ

実装・動作確認、Delphi XE5にて行ったのですが、なーぜーかリリースビルドであるにもかかわらず、Assertの生成がONになってた。
リリースビルドではAssertのコードを生成しないのが一般的だと思ってたので、ちょっと驚いた。

まぁ古いバージョンだし、今は昔で変わってるのかな?

10
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2