配列へのポインタ型へのキャストの方法

解決


ゆうこ  2006-01-17 20:05:17  No: 19707

Word型(2byte)変数に文字コードが入っており、
その値を文字として扱いたいため、String型変数に
代入して処理を行いたいと考えています。

例えばWord型変数2byteに0x3131が入っていた場合は
String型変数を'11'としたいです。
方針はWord型変数のアドレスをChar型配列(要素数2)への
ポインタとみなしてキャストし、String型変数に代入するのが
良いかと思っています。
しかし、キャストの記載方法がわかりません。
どのような記載方法になるのでしょうか?

//***********************//
// イメージ              //
//***********************//
w_moji:Word;
c_moji:array[0..1] of Char;
str:String

Str := c_moji;             // ←2byteの文字列として認識してくれるので
Str := (キャスト)w_moji;   // ←こうしたいが(キャスト)記載方法が不明

//***********************//
// Cで書くと以下のような //
//***********************//
char (*ptest)[2];        // char型配列(要素数2)へのポインタ宣言
char *pc;                // char型へのポインタ宣言

// char型へのポインタをchar型配列(要素数2)へのポインタにキャストして代入
ptest = (char(*)[2])pc;
        ~~~~~~~~~~~~
宜しくお願いします。


えーと  2006-01-17 20:11:13  No: 19708

>例えばWord型変数2byteに0x3131が入っていた場合は
>String型変数を'11'としたいです。

procedure TForm1.Button1Click(Sender: TObject);
var
  w: word;
  s: string;
begin
  w :=$3131;
  SetLength(s,2);
  Move(w, s[1], SizeOf(Word));
  Label1.Caption := s;
end;


ゆうこ  2006-01-17 21:01:56  No: 19709

えーとさん、早速の回答ありがとうございます。
記載しておりませんでしたが、現在はえーとさんから提示頂いたのと
同じようなで方法で行っております。

今回は、要素数2のChar型配列へのポインタとしてキャストすれば、
簡単に記載できるのではないかと思い質問させていただきました。
提示頂いたソースコードもそうですが、現在の処理ですと、
・SetLengthで長さを設定
・Move関数で文字列をコピー
と2ステップになっていますが、これをキャストだと1ステップで行えるのではないかと思いまして。

※コンパイラ後の実行コードは大差ないのかもしれませんが・・・


大差なし  2006-01-17 21:34:01  No: 19710

半角2文字の文字列変数の格納エリアは2バイトではないので、単なるキャストは不可能。
なので、どうしても、コピーが必要。
キャストした場合でも、内部でDelphiがコピーしていることもある。
※「自分でどこまで試したか書かないのは非礼にあたる」とツッコミを入れてみる。


こんなんじゃだめ?  2006-01-17 22:13:49  No: 19711

procedure TForm1.Button1Click(Sender: TObject);
var
  w: word;
begin
  w :=$3132;
  Label1.Caption := Char(HiByte(w)) + Char(w AND $FF);
end;


にしの  2006-01-17 22:31:22  No: 19712

裏技的に、
var
  w: Word;
  lw: LongWord;
begin
  w := $3132;

  lw := w;
  Label1.Caption := PCHAR(@lw);
end;


ゆうこ  2006-01-18 00:57:33  No: 19713

大差なしさん、こんなんじゃだめ?さん、にしのさん
ありがとうございます。

大差なしさん
>半角2文字の文字列変数の格納エリアは2バイトではないので、単なるキャストは不可能。
>なので、どうしても、コピーが必要。
>キャストした場合でも、内部でDelphiがコピーしていることもある。
はい。
今回はそのコピーを明示的に行わず、String型への値の代入により
プログラマが意図せず行いたかったです。
------------------------------
c_moji:array[0..1] of Char;
Str:String;

Str := c_moji
------------------------------
要素数2のChar型配列へのポインタをString型に
代入する時に行う処理(思いつくところでは、データのコピー、
Lengthの設定)を暗黙的に行いたかったというものです。

>※「自分でどこまで試したか書かないのは非礼にあたる」
不快な思いをさせてしまい、申し訳ありません。

こんなんじゃだめ?さん
>Label1.Caption := Char(HiByte(w)) + Char(w AND $FF);
ありがとうございます。
参考にさせていただきます。

にしのさん
>Label1.Caption := PCHAR(@lw);
ありがとうございます。
文字列操作のこのあたり苦手のため質問させてください。
一度LongWord型に値を代入しているのは
文字列の終端(0x00)を強制的に作るためでしょうか?

C言語では単純にキャストできたので、質問させて頂いたのですが
Delphiでは、その機能はないのでしょうか・・・・


えーと  2006-01-18 02:33:46  No: 19714

> C言語では単純にキャストできたので、質問させて頂いたのですが

C には string 型相当は無いはずですが。文字列を指すポインタだからキャストは簡単。
今回の問題は、Delphi固有の string 型へのキャストですから、大差なしさんの
おっしゃるとおり、コピーする必要があると思います。そうでないと長さを確定
できません。


ゆうこ  2006-01-18 03:03:17  No: 19715

えーとさん、ありがとうございます。

>C には string 型相当は無いはずですが。
String型へのキャストではなく、要素2のChar型配列へのポインタへの
キャストのことを言っています。
また、String型変数へ要素2つのChar型配列へのポインタを代入すると、
------------------------------
var
  c_moji:array[0..1] of Char;
  Str:String;
begin
  c_moji[0] := #$31;
  c_moji[1] := #$31;

  Label1.Caption := IntToStr(Length(Str)); // ←0です
  Str := c_moji;
  Label2.Caption := IntToStr(Length(Str)); // ←2です
  Str := PCHAR(@c_moji[0]);
  Label3.Caption := IntToStr(Length(Str)); // ←5でしたが、不定と思います
------------------------------
要素2のChar型配列へのポインタをString型へ代入すると長さ2の文字列が入るようなので、
Word型の変数のアドレスを同様にキャストして代入できないものかと思いました。

なので
>今回の問題は、Delphi固有の string 型へのキャストですから
String型へのキャストするのが出来ないと言っているわけではなく
要素2のChar型配列へのポインタへのキャストが出来ないと言うことで
>そうでないと長さを確定できません。
これも解決できるのかと考えた次第です。
わかりずらくてすみません。


ん?  2006-01-18 05:48:15  No: 19716

実はわかっていないが、こういうこと?

type
  TWChar= array[0..1] of Char;
  PTWChar= ^TWChar;
var
  w:Word;
begin
  w := $3132;
  Label1.Caption := PTWChar(@w)^;
end;


ゆうこ  2006-01-18 18:18:52  No: 19717

ん?さん
ありがとうございます
はい。
イメージはその通りです。

自分で型宣言をしているのですが、
これを自分で型宣言をせず、
単純に配列へのポインタへのキャストというのは
Delphiでは出来ないのでしょうか?


えーと  2006-01-18 19:06:11  No: 19718

> 単純に配列へのポインタへのキャストというのは

だから、できますけどヌル止めがないと長さがわからない、ってことでしょう。


ゆうこ  2006-01-18 19:14:42  No: 19719

>> 単純に配列へのポインタへのキャストというのは
>だから、できますけどヌル止めがないと長さがわからない、ってことでしょう。

すみません。
要素数2の配列へのポインタへのキャストという意味です。
~~~~~~~~
それが出来ると、String型へ代入するときに
暗黙的に長さがわかるのではないかと言っています。

↓で長さが2になるのは、c_moji[2]の位置にたまたまヌルが入っていた
  わけではなく、Delphiコンパイラ(?)が暗黙的にString型変数への代入時に
  長さを設定しているのではないかと思っているのですが・・・

------------------------------
var
  c_moji:array[0..1] of Char;
  Str:String;
begin
  c_moji[0] := #$31;
  c_moji[1] := #$31;

  Str := c_moji;        // ←要素数2のChar型配列へのポインタをString型変数へ代入
  Label1.Caption := IntToStr(Length(Str)); // ←2です
------------------------------


  2006-01-18 20:26:51  No: 19720

> c_moji:array[0..1] of Char;
はChar型の配列であって要素数2の配列型ではありません。
キャストする要素数2の型が欲しければ、んさんが書いてるように宣言が必要です。

> Str := c_moji;        // ←要素数2のChar型配列へのポインタをString型変数へ代入
これが出来るのは長い文字列型とパック文字列型には代入互換性があるからです。
詳しくはヘルプで型の代入互換性、型の同一性を読んで下さい。


ゆうこ  2006-01-18 20:48:49  No: 19721

sさん、ありがとうございます。

>> c_moji:array[0..1] of Char;
>はChar型の配列であって要素数2の配列型ではありません。

わたしの認識不足かもしれませんが、
  c_moji:array[0..1] of Char;
と宣言し、
  c_mojiと記載する方法は
c_mojiの0番目の要素のアドレスを意味するとの認識でいるのですが、
------------------------------
var
  c_moji:array[0..1] of Char;
  Str:String;
begin
  c_moji[0] := #$31;
  c_moji[1] := #$31;

  Str := c_moji;        // ←要素数2のChar型配列へのポインタをString型変数へ代入
  Label1.Caption := IntToStr(Length(Str)); // ←2です
------------------------------
とした場合
Strの長さはなぜ2とわかるのでしょうか?
c_moji[2]のアドレスの位置にはヌルは入っていませんでした。
わたしは、sさんから提示頂いたように
>代入互換性
によって、c_mojiは「要素2のChar型配列へのポインタ」である
ということをコンパイラが認識して暗黙的に
String型変数に長さ2を設定していると考えているのですが。


ゆうこ  2006-01-18 21:04:31  No: 19722

sさん

>c_mojiの0番目の要素のアドレスを意味するとの認識でいるのですが、
↑わたしのこの認識は、間違っていたようです。
今テストしてわかったのですが、
-----------------------------------------
  Str := PCHAR(c_moji);              //コンパイルエラー
  Str := PCHAR(@(c_moji[0]));        //エラーにならず
-----------------------------------------
上の結果から、c_mojiとの記載方法は、
c_moji[0]のアドレスという意味ではないのですね・・・

-----------------------------------------
Str := c_moji;
-----------------------------------------
とすると、Strは長さがわかっているので

要素数2のChar型配列型の変数そのものという意味???
でしょうか。

ということは、「要素数2のChar型配列へのポインタ型」へのキャスト
ではなく、「要素数2のChar型配列」へのキャストをすると
String型変数へ値を代入できることになり
結論として「要素数2のChar型配列」へのキャストというのは
>キャストする要素数2の型が欲しければ、んさんが書いてるように宣言が必要です。
ということでしょうかね?


s  2006-01-18 22:44:26  No: 19723

> Strの長さはなぜ2とわかるのでしょうか?
これは

> コンパイラが認識して暗黙的に
> String型変数に長さ2を設定していると考えているのですが。

この通りです。配列の長さを認識しています。

> 上の結果から、c_mojiとの記載方法は、
> c_moji[0]のアドレスという意味ではないのですね・・・
> 要素数2のChar型配列型の変数そのものという意味???
> でしょうか。

はい、配列全体を指しています。
(ちなみにC言語でもsizeofの中では配列名で配列全体を指すことになります)

> 結論として「要素数2のChar型配列」へのキャストというのは
> >キャストする要素数2の型が欲しければ、んさんが書いてるように宣言が必要です。
> ということでしょうかね?

でいいと思います。


ゆうこ  2006-01-19 00:54:32  No: 19724

sさん、ありがとうございます。

ようやく納得することが出来ました。

>ちなみにC言語でもsizeofの中では配列名で配列全体を指すことになります
C言語の場合、配列名だけだとポインタを示す!と思っていたのでテスト
してみたのですが、sさんの仰るとおり、sizeofでは
----------------------------------------------
  int a,b,c,d;
  char hairetsu[100];
  
  a = sizeof(hairetsu);
  b = sizeof((char(*)[100])(&hairetsu[0]));
  c = (int)hairetsu;
  d = (int)((char(*)[100])&hairetsu[0]);
----------------------------------------------
a→100
b→4
cとdはどちらも同じアドレスを示していました。

C言語からして理解出来ていなかったようです。
みなさま、ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加