質問: str; fclose(fp); // ファイルを閉じる return ans; } ``` メモ帳の中身は 以前までは「100000」などの数列でしたが これからは「1FFE00」などの16進数を 扱うので文字列で読み込みたいと考えていました。 ご質問なのですが、そもそも こういった文字列を返すことは可能でしょうか? また、受け取り側がC++とC#では中身が変わってくるのでしょうか? ご教示の程よろしくお願い致します。 備考 考察側のソフトに関しては、私の勉強不足で 参考書等やサイトを見ながら手探りでやっています。 間違いが多いみたいです。すいません。
回答: ちょっとまって、それ以前に ``` MEMO_READ char* MEMO_READ(void) { FILE *fp; char fname[] = "c:\\memotyou.txt"; char str[N]; char* ans = 0; fopen_s(&fp, fname, "r");// ファイルを開く if (fp == NULL) { printf("%s file not open!\n", fname); } fgets(str, N, fp); ans = str; fclose(fp); // ファイルを閉じる return ans; } ``` これ、無効なポインタを返しています。 追記 C#の場合はもういっそC++/CLIでDLLをつくるほうが楽ですが(GC的に) ref: c# - C#でC++のDLLから文字列を受け取る - スタック・オーバーフロー C++の場合もDLLと呼び出し側のコンパイラを揃えないといけないですが、いっそC++で作って最初から`std::string`を渡すほうが楽です。 それでもなおC APIにこだわるということでしたら以下を読んで下さい。 基本的にC APIで文字列をかえすには、文字列を格納するメモリを動的に確保する必要があります(`malloc`とかで)。 ということはそのメモリーは開放しないといけないですね。 ここで2つの戦略が考えられます。 戦略1: 先に文字列の長さを通知して、呼び出し側でメモリーを確保してもらい、そこに書き込む ============================================== つまり ``` size_t c_api_return_string(char* out, size_t out_size); ``` のようなAPIがあったとき、 ``` std::string c_api_return_string_wrap() { const auto len = c_api_return_string(nullptr, 0); std::string str; str.resize(len); c_api_return_string(&str[0], str.size()); str.resize(std::char_traits::length(str.c_str()); return str; } ``` のようなラップ関数がC++側でかけるわけです。 利点としては、予め長さを求めるコストが無視できる場合、メモリー確保回数やコピーを最小限にでき、またDLL側で開放関数を用意せずに済むという点です。 例では文字列の長さ通知と文字列返却を`c_api_return_string`で両方共やっていますが、別に関数を分けても構いません。(C#を考えるなら分けたほうがいい・・・?) 欠点は、予め長さを求めるコストが無視できない場合には使えないことです。 戦略2: DLL側でメモリー確保して返却 ===================== ``` char* c_api_return_string(); void free_c_api_return_string(char*); ``` のようなAPIに対して ``` std::string c_api_return_string_wrap() { char* tmp = c_api_return_string(); std::string re = tmp; free_c_api_return_string(tmp); return tmp; } ``` のようなラップ関数がC++側でかけるわけです。 利点・欠点は先の逆ですので割愛します。