■86106 / inTopicNo.9) |
Re[1]: C入門 |
□投稿者/ 魔界の仮面弁士 (1511回)-(2017/12/18(Mon) 19:02:31)
|
2017/12/18(Mon) 19:18:18 編集(投稿者)
■No86095 (masa さん) に返信 > 当方、VB系の経験しかなく
自分の専門分野も Visual Basic なので、 質問は「C入門」ですが、VB 系の視点で伸べてみます。
> C系の学習(特にデータ型)をする必要があると感じています。
ゴールが見えていないと【手段】と【目的】が入れ替わってしまいそうです。 その学習は、何のために必要としているのでしょうか?
今回の話は、いわゆる低レベル処理になりますので、 目的が明かされないまま手段を問われても答えにくいかと思います。
構造体などは自作できるので、ここでいうデータ型というのが 言語機能で組み込まれた基本型のみを指しているのか、あるいは 特定のプラットフォーム向けに限定した話なのかで、 学習する方向も変わってくるかと思いますよ。
もし、Win32 SDK での開発をターゲットにしているわけではなく、 単純な C 言語の学習という点だけに限定した話であるのなら、データ型のメモリ構造に関する 最低限の知識は、既にあるような印象を受けました。それで十分かどうかは別として。
> Cで作成された関数をコールする場合、 > VBにないデーター型は、サイズが同じ類似の型で代用するわけですが、
たとえば VB/VBA 内で完結する処理に限定するのなら、「データ型」の構造に関しては ヘルプに載っている以上の知識が必要になることはそうそう無いでしょう。
しかし、他のプラットフォームとのデータ交換・マーシャリングが発生するのなら、 どのプラットフォームとやりとりするのか、個別の知識が必要になってきます。 ですから、学習するにしても「目的」ははっきりさせておくべきかと。
■No86101 (masa さん) に返信 > おっしゃる通りVBからのマーシャリングに関する事でCの知識 > を深めたいと思っています。
VB/VBA からの Declare 呼び出しで必要な知識を得ることが目的なのでしょうか。
たとえば、Visual Basic で利用可能な DLL を作成するのが目的だとしても、 「VBA から Declare で利用可能な DLL を作る場合」 「VBA から呼び出し可能な ActiveX DLL を作る場合」 「VBS から呼び出し可能な ActiveX DLL を作る場合」 では、それぞれ求められる知識が微妙に異なります。 (もちろん、共通する部分も多いですが)
VBScript が相手なら、Variant 型前提で設計せねばならず、かつその場合、 VT_BYREF の受け渡しについても異なってきたりします。 http://program.station.ez-net.jp/special/vc/atl-com/variant.asp
VBA と VB.NET でもかなり違いがあります。
たとえば WindowFromPoint API などは、 HWND WindowFromPoint(POINT Point); という定義になっており、引数の型が LPPOINT ではなく POINT です。
VBA の場合、ユーザー定義型を値渡しできないので、 stdcall 規約に従い、引数を展開して (ByVal xPoint As Long, ByVal yPoint As Long) As OLE_HANDLE などと定義しますが、VB.NET の場合は構造体の値渡しが可能なので、 (ByVal Point As POINTAPI) As IntPtr のような宣言が可能です。
この他、.NET Framework と Unamaged DLL の間での Platform Invoke(P/Invoke) や .NET Framework と ActiveX DLL の間での COM Interop などにおいても、 .NET 側のマーシャリングルールに関する知識が必要になります。 http://www5b.biglobe.ne.jp/~yone-ken/VBNET/Reference/ref2_GetPrivateProfileString.html https://msdn.microsoft.com/ja-jp/library/eshywdt7.aspx https://msdn.microsoft.com/ja-jp/library/s9ts558h.aspx (特には OS の違いや、.NET バージョンの違いも考慮せねばならないことがあります)
このような事情もあるので、単純にそれぞれのデータ型(たとえば Decimal)の 内部構造を把握していく学習スタイルは、効果が薄いかと思います。
API に限った話ではなく、VB からの単純なバイナリファイルの入出力でさえ、 手順が変われば、その際のデータ構造は大きく異なってきます。
例として、VBA の「Put ステートメント」のヘルプを見てみると 可変長文字列変数の出力に際して
『文字列の長さを示す 2 バイトの記述子を書き込み、 次に変数内の文字列データを書き込みます。』
という記載があります。
この仕様は BSTR の構造に似ており、最初の 2 バイトは、BSTR でいうとことの オフセット -4 にあるサイズ情報に相当しますが、だからといって、 Put #/Get # を行う際に、BSTR の仕様を把握している必要があるかと問われれば、 その答えは 否 でしょう。
仮に BSTR の仕様を把握していたとしても、レイアウトとしては同じではありませんから、直接は関係しません。 たとえば、BSTR が持つ終端 NULL 部はデータとしては余剰なので出力されませんし、文字列本体部も 元のバイナリではなく CP932(というか、OS 既定のコードページ)への文字コード変換が行われてしまうためです。
もう一つ例を挙げると、同じく VBA ヘルプの「Put ステートメント」において、 配列を出力する場合に、識別子として「(2 + 8 * 配列の次元数)バイト」分の領域が 消費されるとあります。これの内訳も、VB のヘルプ内では明確にされていません。
https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/put-statement https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/get-statement
SAFEARRAY 構造体の仕様を知っていれば、この識別子の内訳を知る手がかりにはなりますが、 だからといって、SAFEARRAY の仕様を知らなければならないかは別問題ですよね。
しかもこの件に関しては、ヘルプの解説さえも間違っています。ここの記述では Dim MyArray(1 To 5,1 To 10) As Integer が 118 バイト(= 2 + 8 * (5 * 10 * 2)) になると書かれていますが、 実際にはこの場合、100 バイトしか確保されない仕様です。
これが 118 バイトになるパターンというのは、 Private Type UDT MyArray() As Integer End Type なユーザー定義型を Dim t As Test ReDim t.MyArray(1 To 5, 1 To 10) As Integer と確保していた場合であり、この場合の内訳は、 [00-01] 2 バイト 02,00 … 次元数 2 を意味する / cDims [02-05] 4 バイト 0A,00,00,00 … 1 次元目の要素数10 を意味する / rgsabound[0].cElements [06-09] 4 バイト 01,00,00,00 … 1 次元目の下限値 1 を意味する / rgsabound[0].lLbound [0A-0D] 4 バイト 05,00,00,00 … 2 次元目の要素数 5 を意味する / rgsabound[1].cElements [0E-11] 4 バイト 01,00,00,00 … 2 次元目の下限値 1 を意味する / rgsabound[1].lLbound [12-75] 配列データの本体 100バイト ( となります。
そしてこれも、SAFEARRAY 構造体のバイナリ構造と類似はしていますが、同一ではありません。 データと直接関係の無い Features / cbElements / cLocks 等は確保されません。
|
|