ビジネス WinDbgアプリケーション開発技術 イメージロード(ユーザモードとカーネルモード)


C++とprintf関数

 私たちは現在、次のようなC++ソースコードの意味と背景を考えています。
#include <iostream>

int main()
{
  const std::string ch0 = "Typical: I don't know anything about programming!\n";
  const std::string ch ("Simplified form: I don't know anything about programming!\n");
  const std::string* ch1 =  new std::string ("Pointer form: I don't know anything about programming!\n");

  std::cout << "Popular: I don't know anything about programming!" << std::endl;
  printf(ch0.c_str());

  std::cout << ch.data();
  std::cout << ch1->data();
  std::cout << ch.c_str();
  std::cout << ch1->c_str();

  std::cout.write(ch.c_str(), ch.size());
  std::cout.write(ch1->c_str(), ch1->size());
  
  delete ch1;
  return int(0);
}
 このC++ソースコードは、私たちに次のいずれかの印象を与えています。すでに説明済みの項目は、打ち消されています。

印象1:とにかく難しい!
印象2:Cのソースコードとどこか似ている
印象3:#includeに続くiostreamという意味が分からない

印象4:stdio.hがないにもかかわらず、printf関数が呼び出されていることが不思議だ!
印象5:std::coutのstdの意味が分からない
印象6:std::coutの「::」の意味が分からない
印象7:std::coutのcoutの意味が分からない
印象8:「<<」の意味が分からない
印象9:std::endlのendlの意味が分からない
印象10:「std::string ch」のstringの意味が分からない
印象11:「std::string ch」のchの意味が分からない
印象12:ch.data()の意味が分からない
印象13:ch.c_str()の意味が分からない
印象14:std::cout.writeの意味が分からない
印象15:ch.size()の意味が分からない
印象16:std::string*の「*」の意味が分からない
印象17:std::string* ch1の「ch1」の意味が分からない
印象18:ch1->data()の意味が分からない
印象19:ch1->c_str()の意味が分からない
印象20:ch1->size()の意味が分からない

 今回は、「印象4:stdio.hがないにもかかわらず、printf関数が呼び出されていることが不思議だ!」の意味を考えます。ソースコードには、確かに、「stdio.h」というファイルはありません(つまり、インクルードされていません)。このファイルはその名称が示しているように、「標準入出力(standard I/O)機能の利用法を定めた(インターフェイス定義)ファイル」です。そして、このファイルはCの標準化委員会が定めたものですから、C++標準化委員会もその存在を尊重する必要があります。

 「stdio.h」ファイルがインクルードされていないにもかかわらず、なぜCの世界のprintf関数が実行されるのでしょうか。結論を急げば、「stdio.h」ファイルは表面に出ていないだけで、前回取り上げた「iostream」ファイル内から間接的にインクルードされているのです。次の情報をご覧ください。内容のすべてを理解できる必要はもちろんありません。
// cstdio standard header
#pragma once
#ifndef _CSTDIO_
#define _CSTDIO_
#include <yvals.h>

#ifdef _STD_USING
 #undef _STD_USING
  #include <stdio.h>
 #define _STD_USING

#else /* _STD_USING */
 #include <stdio.h>

 #if _GLOBAL_USING
_STD_BEGIN
using ::size_t; using ::fpos_t; using ::FILE;
using ::clearerr; using ::fclose; using ::feof;
using ::ferror; using ::fflush; using ::fgetc;
using ::fgetpos; using ::fgets; using ::fopen;
using ::fprintf; using ::fputc; using ::fputs;
using ::fread; using ::freopen; using ::fscanf;
using ::fseek; using ::fsetpos; using ::ftell;
using ::fwrite; using ::getc; using ::getchar;
using ::gets; using ::perror;
using ::putc; using ::putchar;
using ::printf; using ::puts; using ::remove;
using ::rename; using ::rewind; using ::scanf;
using ::setbuf; using ::setvbuf; using ::sprintf;
using ::sscanf; using ::tmpfile; using ::tmpnam;
using ::ungetc; using ::vfprintf; using ::vprintf;
using ::vsprintf;
_STD_END
 #endif /* _GLOBAL_USING */

#endif /* _STD_USING */
#endif /* _CSTDIO_ */
 このようなヘッダファイル情報を見ても、見慣れないうちはどことなく難解な印象を受けてしまいます。筆者個人は、「stdio.h」や「iostream」などのヘッダファイルを「インターフェイス定義ファイル」と呼んでいます。インターフェイス定義ファイルの内容を理解できるようになれば、たとえば、次のようなソースコードも書けるようになります(VS 2003.NET環境で動作確認済み)。

(オリジナルコード)
printf(ch0.c_str());

(インターフェイス定義ファイルを参考にしたコード)
::printf(ch0.c_str());
std::printf(ch0.c_str());

 たいへん面白いコードです。CやC++のベテラン開発者でも、もしかすると、このようなコードを今日初めて目にした方もいらっしゃるのではないでしょうか。「C++の世界がCの世界を包み込みながら」時代が進んでいるような感じがします。今回は、次のような点をしっかり覚えておきましょう。

 "「std::printf(ch0.c_str());」というコードは、C++の世界は思想的にCの世界を内包してしまっていることを示している。"

 「std::printf」というコーディングスタイルは、このように使われます。インターネットから一般公開されている情報資源を活用できる力をまず身に付けましょう!そのためには、分からないところを自分なりに解明し、日々しっかり基礎訓練を積むんでおくことが大切だと思います。独創的なアルゴリズムを実装したり、低レベルのシステム関数を使用する場合は別にして、平均的なアプリケーションの開発作業の大半は、実際上、インターネット上の(英文)情報の解読作業そのものです。

前へ | 次へ




 WinDbg入門  ホーム


Copyright©豊田孝 2004- 2009
本日は2009-01-06です。