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

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

ただいまの
回答率

88.58%

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 5,403

nodact

score 33

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

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

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

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

//現状の数列を返すソフト

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#define N 36 // 1行の最大文字数(バイト数)

MEMO_READ int MEMO_READ(void) {
    FILE *fp; 
    char fname[] = "c:\\memotyou.txt";
    char str[N];
    int ans = 0;
    fopen_s(&fp, fname, "r");// ファイルを開く
    if (fp == NULL) {
        printf("%s file not open!\n", fname);
    }

    fgets(str, N, fp);
        ans = atoi(str);

    fclose(fp); // ファイルを閉じる
    return ans;
}
//考察したソフト

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#define N 36 // 1行の最大文字数(バイト数)

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;
}


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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

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<char>::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++側でかけるわけです。

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/03 23:54

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

    キャンセル

  • 2018/02/04 01:09

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

    キャンセル

  • 2018/02/06 15:51

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

    キャンセル

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

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る