質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

9823閲覧

C言語の戻り値がchar*のDLLプログラムについて

nodact

総合スコア41

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/02/02 06:57

編集2018/02/02 07:50

この質問を見ていただきましてありがとうございます。
早速掲題の件ですが、調べても答えが見えなかったので
質問させていただきます。

やりたいこと
1.メインプログラムからDLLを呼び出す。
2.DLLでは指定された場所のメモ帳から文字列を読み込みメインプログラムに返す。
3.受け取る側はstring(文字列形式)受け取りたい。
※受け取る側はC++かC#の2つの可能性があります。

現状ある動いているソフトを改造して行いたかったのですが、
なかなかうまくいきません。

現状のソフトは数値を読み込むものですが
これを文字列を読み込めるようにしたいです。

C++

1//現状の数列を返すソフト 2 3#include "stdafx.h" 4#include <stdio.h> 5#include <stdlib.h> 6 7#define N 36 // 1行の最大文字数(バイト数) 8 9MEMO_READ int MEMO_READ(void) { 10 FILE *fp; 11 char fname[] = "c:\memotyou.txt"; 12 char str[N]; 13 int ans = 0; 14 fopen_s(&fp, fname, "r");// ファイルを開く 15 if (fp == NULL) { 16 printf("%s file not open!\n", fname); 17 } 18 19 fgets(str, N, fp); 20 ans = atoi(str); 21 22 fclose(fp); // ファイルを閉じる 23 return ans; 24}

C++

1//考察したソフト 2 3#include "stdafx.h" 4#include <stdio.h> 5#include <stdlib.h> 6 7#define N 36 // 1行の最大文字数(バイト数) 8 9MEMO_READ char* MEMO_READ(void) { 10 FILE *fp; 11 char fname[] = "c:\memotyou.txt"; 12 char str[N]; 13 char* ans = 0; 14 fopen_s(&fp, fname, "r");// ファイルを開く 15 if (fp == NULL) { 16 printf("%s file not open!\n", fname); 17 } 18 19 fgets(str, N, fp); 20 ans = str; 21 22 fclose(fp); // ファイルを閉じる 23 return ans; 24}

メモ帳の中身は
以前までは「100000」などの数列でしたが
これからは「1FFE00」などの16進数を
扱うので文字列で読み込みたいと考えていました。

ご質問なのですが、そもそも
こういった文字列を返すことは可能でしょうか?
また、受け取り側がC++とC#では中身が変わってくるのでしょうか?
ご教示の程よろしくお願い致します。

備考
考察側のソフトに関しては、私の勉強不足で
参考書等やサイトを見ながら手探りでやっています。
間違いが多いみたいです。すいません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ちょっとまって、それ以前に

cpp

1MEMO_READ char* MEMO_READ(void) { 2 FILE *fp; 3 char fname[] = "c:\memotyou.txt"; 4 char str[N]; 5 char* ans = 0; 6 fopen_s(&fp, fname, "r");// ファイルを開く 7 if (fp == NULL) { 8 printf("%s file not open!\n", fname); 9 } 10 11 fgets(str, N, fp); 12 ans = str; 13 14 fclose(fp); // ファイルを閉じる 15 return ans; 16}

これ、無効なポインタを返しています。


追記

C#の場合はもういっそC++/CLIでDLLをつくるほうが楽ですが(GC的に)
ref: c# - C#でC++のDLLから文字列を受け取る - スタック・オーバーフロー

C++の場合もDLLと呼び出し側のコンパイラを揃えないといけないですが、いっそC++で作って最初からstd::stringを渡すほうが楽です。

それでもなおC APIにこだわるということでしたら以下を読んで下さい。

基本的にC APIで文字列をかえすには、文字列を格納するメモリを動的に確保する必要があります(mallocとかで)。
ということはそのメモリーは開放しないといけないですね。

ここで2つの戦略が考えられます。

戦略1: 先に文字列の長さを通知して、呼び出し側でメモリーを確保してもらい、そこに書き込む

つまり

c

1size_t c_api_return_string(char* out, size_t out_size);

のようなAPIがあったとき、

cpp

1std::string c_api_return_string_wrap() 2{ 3 const auto len = c_api_return_string(nullptr, 0); 4 std::string str; 5 str.resize(len); 6 c_api_return_string(&str[0], str.size()); 7 str.resize(std::char_traits<char>::length(str.c_str()); 8 return str; 9}

のようなラップ関数がC++側でかけるわけです。

利点としては、予め長さを求めるコストが無視できる場合、メモリー確保回数やコピーを最小限にでき、またDLL側で開放関数を用意せずに済むという点です。

例では文字列の長さ通知と文字列返却をc_api_return_stringで両方共やっていますが、別に関数を分けても構いません。(C#を考えるなら分けたほうがいい・・・?)

欠点は、予め長さを求めるコストが無視できない場合には使えないことです。

戦略2: DLL側でメモリー確保して返却

c

1char* c_api_return_string(); 2void free_c_api_return_string(char*);

のようなAPIに対して

cpp

1std::string c_api_return_string_wrap() 2{ 3 char* tmp = c_api_return_string(); 4 std::string re = tmp; 5 free_c_api_return_string(tmp); 6 return tmp; 7}

のようなラップ関数がC++側でかけるわけです。

利点・欠点は先の逆ですので割愛します。

投稿2018/02/02 07:22

編集2018/02/02 08:20
yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nodact

2018/02/02 07:48

ご回答ありがとうございます。 すいません、私の勉強不足です。 完全に良かれと思ってやってます。 修正したらこの構想でできそうなのでしょうか? お手数をおかけしますがよろしくお願いいたします。
yumetodo

2018/02/02 07:50

>受け取る側はC++かC#の2つの可能性があります。 どっちなのか決めてから質問してください
nodact

2018/02/02 07:52

C++でお願いいたします。 現状両方で受け取ることがありそういった記述をさせていただきました。 やはり、C++とC#ではDLL側も変わってくるのでしょうか? 何卒よろしくお願い致します。
hmmm

2018/02/02 12:32

ja.stackoverflowのその質問を引用するのであれば、::CoTaskMemAllocを使用する方法が個人的にはベターだと思います。
yumetodo

2018/02/02 13:19

>::CoTaskMemAllocを使用する方法が個人的にはベターだと思います。 はい、ですから >C#の場合はもういっそC++/CLIでDLLをつくるほうが楽ですが と冒頭に書きました。
asm

2018/02/02 15:35

DLL側でメモリ確保する場合は欠点として、「誰がメモリを解放する責任をもつのか」という問題があります。 特にmalloc/freeを用いる場合、DLLとメインモジュール(exe)でmalloc/freeの実装が異なる事があります。
yumetodo

2018/02/02 15:37

回答本文でもDLL側でメモリ確保する場合は開放用関数が必須であることを踏まえて回答したつもりでしたが、補足ありがとうございます
hmmm

2018/02/03 14:54

::CoTaskMemAllocとC++/CLIは関係ないと思いますがどういう意味でしょうか?。::CoTaskMemAllocを使用すると、.Net側でGC対象することができ解放する処理を考えなくてよくなります。https://ja.stackoverflow.com/a/31640
yumetodo

2018/02/03 16:09

>::CoTaskMemAllocとC++/CLIは関係ないと思いますが あべし、やらかした。あいつはCOMだったか。
nodact

2018/02/06 06:51

やっと実装が完了しました。 皆様のアドバイスありがとうございました。 遅くなりましたが、ベストアンサーとさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問