甲府方重信Blog

...Shigenobu Koufugatas Blog

  • Increase font size
  • Default font size
  • Decrease font size
Error
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
  • Unable to load Cache Storage: database
Home 業務日誌 Adaプログラミング Adaチュートリアル セクション16.2 - C言語とのインターフェース

Adaチュートリアル セクション16.2 - C言語とのインターフェース

E-mail Print PDF

セクション 16.2 - C言語とのインターフェース

C言語から呼び出される可能性のある多くの有益なユーティリティが存在するので、AdaからC言語をどのように呼び出すかを知っておくのは良いアイディアです。このセクションは、プログラマーが一定の基本的なレベルでC言語について知っていることを仮定しています。; もしプログラマーがC言語について知らないのであれば、このセクションは読み流すだけで結構です。

最初に、ここでAdaとC言語をどのように対応させるかについての一般的なルールを示します。これは、RM B.3(63)を基本としています。

  1. Adaのプロシージャーは、voidを返すC関数に対応します。
  2. Adaの関数は、voidでない返り値を返すC関数に対応します。
  3. Adaの配列は、Cのポインターの最初の要素に対応します。
  4. 単純なスカラ型は(integer、floatsとアクセス/ポインター型)は、他の言語の明白な型に対応します。

Ada 95は、C言語とのインターフェースを容易にするための事前定義パッケージのセットを提供しています。基本パッケージは、「Interfaces.C」で、AdaにおけるCの型に対する定義を含んでいます。C言語のint、long、unsigned、doubleの型が含まれています。C言語のfloat型は、「C_float」とAdaでは呼ばれており、それは、AdaのFloat型と混同しないようにするためです。(AdaのFloatとC言語のfloatは、同一のように思えますが、実際はそうではないのです).

「char_array」型は、Cのcharacter配列を模倣します。多くのC言語の関数は、character配列が特別なキャラクター「nul」で終わっていることを仮定しています。(C言語では「\0」と書かれます)。Adaの文字列は、通常、ヌルターミネートではないので、To_C関数とTo_Ada関数がAdaの文字列方とC言語のchar_array型の変換を行います。

Interfaces.C.StringsとInterfaces.C.PointersというC言語スタイルの文字列とポインターのための型と操作を追加するための追加パッケージが存在します。特に、「Interfaces.C.Strings」は、「chars_ptr」型を定義しており、これはC言語の典型的な型「char*」に対応し、C言語の文字列へのポインターに使用されます。(たとえば、キャラクター配列へのポインターなどです) このパッケージは、また以下も定義しています。:

  1. 定数Null_Ptr、これはC言語の(char*)NULLに対応します。
  2. プロシージャーFree、これはC言語のfree()に対応します。
  3. 関数Value、これはchars_ptrを引数にとり、通常のAda文字列を返します。この関数は、ヌルポインターが渡された場合には、Dereference_Error例外を上げます。

実際の例を通して、プログラマーがこれらを実際にどのように動作するかを見ていくことにしましょう。この例は、「package CGI」からとったもので、AdaをWWWのコモン・ゲートウェイ・インターフェース(CGI)と組み合わせたものです。プログラマーがオペレーティングシステムから環境変数の値を取りたいと考えていると想定しましょう。そして、プログラマーは、既存のC関数がこれを実行することを通じて、環境変数の値を取ろうとしていることにします。C言語では、この関数は「getenv」と呼ばれており、これは次のように定義されています。 (次の書籍によります [Kernighan and Ritchie 1988, edition 2, page 253]):

  char *getenv(char *name);

これは、かなりそのままAdaに翻訳することができます。:

  function getenv(Variable : chars_ptr) return chars_ptr;
  pragma Import(C, getenv);

これは動作しますが、Adaプログラムにおいてinとoutの型「chars_ptr」の翻訳された値を保持しなければならない場合には不便です。おそらく、ラッパープログラムを書いて、Ada文字列をC文字列( chars_ptr )に変換し、まさその逆をするようにする方がより良いでしょう。では、そのように動作するAdaの関数を定義します。:

with Interfaces.C.Strings; use Interfaces.C.Strings;
-- ...

 function Get_Environment(Variable : String) return String is
 -- Return the value of the given environment variable.
 -- If there's no such environment variable, return an empty string.
 
   function getenv(Variable : chars_ptr) return chars_ptr;
   pragma Import(C, getenv);
   -- getenv is a standard C library function; see K&R 2, 1988, page 253.
   -- it returns a pointer to the first character; do NOT free its results.
 
   Variable_In_C_Format : chars_ptr := New_String(Variable);
   Result_Ptr : chars_ptr := getenv(Variable_In_C_Format);
   Result : String := Value_Without_Exception(Result_Ptr);

 begin
  Free(Variable_In_C_Format);
  return Result;
 end Get_Environment;

宣言セクションにおいて、たくさんの文字列操作が発生することを覚えておいてください。これは、全体の動作を容易するためであり、シンプルなAda文字列はそれらが一度宣言されると固定の長さを持つためなのです。Value_Without_Exceptionと呼ばれる特定の関数への呼び出しが存在します。; これは、通常ヌルのCのポインターを文字列にしようとしたときに、例外が上がるためです。そして、私たちはそれを空の文字列に変換したいと考えたわけです。このことは、私たちがそのような関数を定義しなければならないということを意味します。; ここで、その定義を示します。:

 function Value_Without_Exception(S : chars_ptr) return String is
 -- Translate S from a C-style char* into an Ada String.
 -- If S is Null_Ptr, return "", don't raise an exception.
 begin
   if S = Null_Ptr then return "";
    else return Value(S);
   end if;
 end Value_Without_Exception;
 pragma Inline(Value_Without_Exception);

さて、私たちはAdaにおいて環境変数を容易に入手できるようになりました。例えば、REQUEST_METHODという環境変数の値を入手したいのであれば、次のようにします。:

  Request_Method_Text : String := Get_Environment("REQUEST_METHOD");

私たちがカバーしていない事項に、C言語の構造体があります。AdaのレコードとC言語の構造体は、はっきりと対応しています。しかし、どのように正確に対応しているのでしょうか。Ada RMは、Adaのレコードが常に対応するC言語の構造体の開始に対し、ポインターとして渡されるべきとアドバイスを与えていますが、要求はしていません。 このため、(比較的まれではあるでしょうが)、C言語の関数が構造体を値渡しとして期待しているようなケース(構造体へのポインターの代わりにコピーが渡される)において、プログラマーは、ポインターを実際の構造体に変換するような新しいC言語の関数を書き、そして、Adaからその新しいC言語の関数を呼び出すようにします。しかしながら、これは単純なアドバイスです。GNATコンパイラーは、このアドバイスに従っていません。 - その代わり、GNATはAdaのレコードを値渡し(コピー)します。どちらのプローチも合理的なものですが、不幸なことにそれらは異なっています。Adaのレコードを渡すための最も安全なアプローチは、常に「access to record」の値を渡すことです。- それらが、スカラーなのであれば、それらは全てのAdaコンパイラーにおいて正しく渡されることが保証されています。

出典: http://www.adahome.com/Tutorials/Lovelace/s16s2.htm

Last Updated on Thursday, 21 June 2012 17:15  

ニュース速報

[リナックスアカデミー]Linuxセキュリティ(企業研修)

企業研修で、受講生は2名。5日間。

企業研修にしては、一日の時間が短いかもしれない。

もう少し演習を増やしたほうがいい。

アンケートの結果は、「満足」「満足」。

講師の評価は、「非常に満足」「満足」。

受講生の皆さん、お疲れ様でした。