文字列を文字の配列に変換時のエラー

解決


yumiko  2009-01-27 14:15:33  No: 69503  IP: 192.*.*.*

文字列を文字の配列に変換しようとしています。(VC++/CLR)
以下のように記述したらエラーがでてしまい試行錯誤しています。


rray< char >^ g_CallNo
の部分を
g_CallNo
と変えてみましたが、同じエラーが出ます。

何が原因なのでしょうか?

【エラー内容】
error C2440: '=' : 'cli::array<Type,dimension> ^' から 'char' に変換できません。

///以下ソースです///////////////////////

#include "stdafx.h"

char g_CallNo[48];

namespace fsend
{
  using namespace System;

  public ref class Form1 : public System::Windows::Forms::Form{

    //中略

    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
      String ^ s = txtbx_CallNo->Text;
      array< char >^ g_CallNo = s->ToCharArray();  
      fsend_Call( g_CallNo );
     }
  };
}

/////////////////////////////////////ここまで////////////

C++学習を始めたばかりなのでそこも加味して、チェックしていただければ幸いです。
不足情報有れば、お伝えください。
よろしくお願いします。

編集 削除
Blue  2009-01-27 14:22:44  No: 69504  IP: 192.*.*.*

System::String::ToCharArray
の戻り値はarray<System::Char>^です。

System::Char は char とは違います。
(Javaのcharの扱いと一緒だけど。)

.NET Frameworkを使うのであれば、charではなくSystem::Char(もしくはwchar_t)を
デフォルトで扱うようにしましょう。

どうしてもcharでなければいけない場合はそのつど文字コード変換してください。
ただし、Unicode→CP932ですとCP932で表現できない文字があると情報が落ちますけど。

編集 削除
yumiko  2009-01-27 15:38:26  No: 69505  IP: 192.*.*.*

Blueさん

分かりやすいご説明ありがとうございます。
Char→System::Charに変え、C2440のエラーは消えました。
勉強になります。

ただ…
ソースの最後の方の、
fsend_Call関数の中で、char型の変数を使っているのですが、
その変数が別プロジェクトと共有しているヘッダファイルに定義されており、
ヘッダファイルを書き換えることができません。

そこで、つど文字コードを変換する方法でやってみようと思います。
(wctomb 関数を使うとよいのでしょうか?)

結果報告を含め、改めて〆させて下さい。

編集 削除
subaru  2009-01-27 15:39:11  No: 69506  IP: 192.*.*.*

System::Charの間違いかな?とは思うけど、一応
System::Runtime::InteropServices::Marshalクラスの
StringToHGlobalAnsi/FreeHGlobal
で一時的にAnsi文字列を得ることもできます。
#変換できない文字はありえます。

編集 削除
επιστημη  URL  2009-01-27 16:31:29  No: 69507  IP: 192.*.*.*

> wctomb 関数を使うとよいのでしょうか?

いいけど呼び出す前に一度だけ locale 設定の呪文を唱えましょう。

編集 削除
yumiko  2009-01-28 16:10:27  No: 69508  IP: 192.*.*.*

subaruさん、επιστημηさん

ありがとうございます。
アドバイスを参考にソースを追加してみました。
が、以下のエラーが出てしまいました。

【エラー内容】
error C2664: 'wcstombs' : 2 番目の引数を 'cli::array<Type> ^' から 'const wchar_t *' に変換できません。

二番目の引数はconstでなければ入らないのでしょうか?
だとすれば、このプログラムの場合、値をテキストボックスから受け取るので、wcstombs関数以外の方法を探さないといけないということ(??)なのでしょうか?

///以下ソースです//////////////////////////////
char  g_CallNo[24];

public ref class Form1 : public System::Windows::Forms::Form{
//中略
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
String ^ s = txtbx_CallNo->Text;
array< wchar_t >^ w_CallNo = s->ToCharArray();//wchr_ban配列に変換  
g_CallNo   = (char)malloc(40);

setlocale(LC_ALL, "ja");
wcstombs( g_CallNo, w_CallNo, 40);//ワイド文字→マルチバイト
fsend_Call( g_CallNo );
 }
};
}

**************************************************

int fsend_Call( char* CallNo ){

}

////////////////////////////ソースここまで/////

何か対処法はあるでしょうか?
どうぞよろしくお願いします。

編集 削除
Blue  2009-01-28 16:23:41  No: 69509  IP: 192.*.*.*

ご参考に
http://social.msdn.microsoft.com/forums/ja-JP/vcexpressja/thread/00caa8bb-35e8-42b7-8721-c602ec1f30cc/

sample1かsample2のやり方が適当かな。

編集 削除
επιστημη  URL  2009-01-28 16:26:09  No: 69510  IP: 192.*.*.*

array<XXX>^ はmanaged配列であり、wcstombsが受け取れるnative配列(ポインタ)とは互換性がありません。
pin_ptrでnative領域に釘留めしてやらにゃならんでしょう。

↓コレではどうでしょうか。

pin_ptr<wchar_t> w_CallNo = &(s->ToCharArray())[0];
wcstombs( g_CallNo, w_CallNo, 40);

編集 削除
yumiko  2009-01-30 13:34:37  No: 69511  IP: 192.*.*.*

Blueさん、επιστημηさん
ありがとうございます。
おかげさまで旨く行きました。
以下に結果載せておきます(変数名少し変わっています)。
勉強になりました。

///以下ソースです//////////////////////////////////////////
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
      
      String^  str_no;    
      char  chr_no[48];
      char *  pt01;
      char *  pt02 = 0;
      array< unsigned char >^   ar_no;
      pin_ptr<const unsigned char>  pi_no;   

      str_no = this->TBX_callNO_ch1->Text;  //TxetBoxの文字列取得
      ar_no = System::Text::Encoding::GetEncoding( L"Shift_JIS" )->GetBytes( str_no );
      pi_no = &ar_no[ 0 ];  //アドレスを代入
      
      strncpy_s(  chr_no,  48,  static_cast<const char*>( static_cast<const void*>( pi_no ) ),   ar_no->Length  );
                
      for(pt01=g_CallNo,  pt01=chr_no;
        '0'<=*pt01&&*pt01<='9';
        pt01++,   pt02++)
        
        *pt01 = *pt02;  //  ポインター操作での代入
        *pt01 = '\0';  //最後にNULL付加

      fsend_Call( g_CallNo ); // 配列渡し
     }
**************************************************

int fsend_Call( char* CallNo ){…}

////////////////////////////ソースここまで/////////////////

string→charは思ったより大変なのですね。
ありがとうございました。

編集 削除
yumiko  2009-01-30 13:35:11  No: 69512  IP: 192.*.*.*

解決です。

編集 削除
επιστημη  URL  2009-01-30 15:09:03  No: 69513  IP: 192.*.*.*

...そんなにめんどくさいかなぁ...

#include <iostream>

int main() {
  System::String^ input = L"このUNICODE文字列をShift_JISに変換する";
  char result[100];
  char* p = result;
  for each ( unsigned char ch in 
             System::Text::Encoding::GetEncoding(L"Shift_JIS")->GetBytes(input) ) *p++ = ch;
  *p = '\0';
  std::cout << '[' << result << ']';
}

編集 削除
yumiko  2009-02-04 14:19:43  No: 69514  IP: 192.*.*.*

επιστημηさん

こんなにすっきりしたコードになるんですね。
ありがとうございます。

編集 削除