C言語の質問です。

mallocなどで確保した任意のメモリ領域をFILE構造体、またはファイルディスクリプタとして扱う方法はないでしょうか?
OSに依存した方法でもかまわないです。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2008/06/08 18:00:15
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答5件)

id:dungeon-master No.1

回答回数571ベストアンサー獲得回数40

ポイント50pt

>mallocなどで確保した任意のメモリ領域をFILE構造体、

>またはファイルディスクリプタとして扱う方法はないでしょうか?

なぜ、そのようなことをしたいのか、まず動機を明らかにした方がよいでしょう。


そもそもFILE構造体や配下の情報について、構造を意識する必要は通常はありません。

(意識しなくても良いように/させることの無いように設計されています。)

FILE構造体配下の定義はコンパイラが提供するヘッダファイルをみればわかりますが、

別のデータ(関数、構造体、ストリームバッファなど)へのポインタだらけです。

ナンセンスな話ですが、仮に、FILE構造体をmallocして与えることができても、

それら別データの領域確保もやらねばなりませんし、IOするたびにどこかの領域を

開放・再確保しなければならないのかもしれません。

しかも環境依存であるので、そういう部分をさわるプログラムはCのバージョンが

変わっただけで使い物にならなくなる可能性が高いです。


大抵のOSではファイルアクセス用のシステムルーチンやライブラリが限定されていて

そのOS上で動く言語が提供するファイルアクセス機能は、それらのシステムルーチンを

呼び出す形で実装されます。

CのファイルIO関数群も、それらのシステムルーチンを呼び出すことになるわけですが、

環境によっては、そちらを呼び出す方法が正式に提供されていることがあります。

当然その場合、FILE構造体を使うアクセス手順とは異なるプログラミングが必要。

管理領域を自前で用意するルールであるいうケースも普通です。

id:winebarrel

すいません。確かに説明不足ですね。

C言語で、ファイルでもメモリでもシームレスに扱う方法がないかなーと思って質問しました。

例えば、read(2)だったら、ファイルでもソケットでもシームレス(な感じ)に扱えますよね?

C言語じゃないですが、Rubyなら、FileもStringIOも同じインターフェースで扱えますよね?

そんな感じで「fprintfを使っているけど、実はメモリに出力している」というようなことができないかな…と。

「sprintfを使え」と言われればそれまでなんですが、メモリでもファイルでもシームレスに操作できる方法があれば、教えていただきたいです。

2008/06/04 21:36:07
id:ahirusan No.2

回答回数229ベストアンサー獲得回数3

ポイント50pt

fopen関数はFILE構造体へのポインタを返してくるので、自分でmallocした領域を利用するのは、不可能ではないものの意味がないのではないでしょうか。fdは単なるintですし。

id:winebarrel

回答ありがとうございます。

上記のコメントの通り、やりたいことはメモリ/ファイルを意識しないような操作です。

分かりづらくて、すいません…

2008/06/04 21:37:53
id:pahoo No.3

回答回数5960ベストアンサー獲得回数633

ポイント50pt

すでに#1さんが回答していますが、mallocしたメモリ空間にファイルディスクリプタを割り当てるのは無理だと思います。


Cは、現在よりはるかにメモリ容量が少ない時代の言語ですので、「入出力」はデバイスに対して行うという概念です。しかも、ファイル以外のデバイスとしては、stdin, stdout, stderr しかありません。


かつてCコンパイラを製造した経験がありますが、たしかに、fopen関数は malloc した空間に FILE 構造体を割り当てることをします。しかし、I/Oバッファの大きさや、バッファリングしたデータを fflush するタイミングはコンパイラ依存です。

gccのライブラリをいじれば目的を達成することができるでしょうが、これをやってしまうと、改造したライブラリがなければ、正常にコンパイルできないプログラムになってしまいます。


RubyやPHPのヒアドキュメントのようなことをやりたいのであれば、sprintfを使えば賄えますから、自前の memopen, memclose, memprintf 関数のような関数を定義し、引数が "mem:" だったらメモリに書き込むようにしたらどうでしょうか(fopen 関数のライブラリを直接改造する代わりに、ユーザー関数を用意するイメージです)

また、malloc にこだわらないのであれば、RAMディスクに対して fopen したらどうでしょうか。

id:winebarrel

回答ありがとうございます。

標準ライブラリを使うのは、やっぱり難しそうですね…

2008/06/08 17:42:56
id:longicorn No.4

回答回数56ベストアンサー獲得回数6

ポイント50pt

1.もし本当にFILE構造体を使いたかったら普段使っているライブラリを修正すれば可能かもしれないです。

あとは関数をフックしてやるとか。


2.ファイルディスクリプタは所詮int型で実体はカーネルが管理しているのでドライバを書く等すれば可能かも。

あとはカーネルを改造してやって、新規関数を作れば可能でしょう。


3.そこまでやる気がないのであれば、自前でopen()等をラップした関数を作成してやって、

自前のmalloc()で作ったデータにもその関数を通して使うように工夫すれば出きるでしょう。


4.番外編でsystem()を使ってRubyを呼べば可能ですよ。

まあ、冗談ですけど。


結局真面目にやるのであれば1,2の方法でしょうけどOSや言語の下位の部分が担当している部分に触らないとどうしようもないです。

現実解としては3の方法になるでしょう。

しかしその前に少し考えてみてください。

そもそも、そのような設計になるのが問題です。C++等のOOPを使えばこの辺は少しはマシになるかと。


5.おまけ。

その他ヒントになるかもしれない関数リストの一部分を挙げておきます。

fdopen(),freopen(),dup(),dup2(),mmap(),mknod()

id:winebarrel

回答ありがとうございます。

>そもそも、そのような設計になるのが問題です。

そうですねー。

そもそも、ファイルしか扱えないライブラリを、簡単にメモリも扱えるようにできないか、というのが根本的な動機だったのですが、そんな使い方するなってことですよね…

2008/06/08 17:46:37
id:pyopyopyo No.5

回答回数377ベストアンサー獲得回数98

ポイント60pt

OSの機能を使えば

  • ファイルをメモリとして読み書き
  • メモリをファイルとして読み書き

どちらでも可能です。

前者のファイルをメモリとして読み書きする方法は、 memory mapped file と言います。

memory mapped file を使うには

  • linuxなどのunix系では mmap()
  • windows系では CreateFileMapping()

という関数を使います。

使い方は、どちらも同じです。たとえば mmap()を使って、"file.txt"というファイルに"hogehoge"という文字列を書き込むには、以下のようなコードを書きます。(実際にはopen()とmmap()にはもう少し引数が必要ですが、以下のコードでは省略しています。)

 int fd = open("file.txt");
 char *p = mmap(fd);

 sprintf(p, "hogehoge");

 munmap(p);
 close(fp);

動作を説明すると、このコードは

  • mmap()を使って、"file.txt"というファイルを、メモリ空間に割り当てる。
  • mmap()が返したアドレス p 以降にsprintf()で文字列を書き込むと、OSが file.txt を更新してくれる

という処理を行っています。

このように memory mapped file を使うと、sprintf()を使っているけど、実はファイルに書き出している、という処理が実現できます。


実際にコンパイル&実行できるソースコードが以下のURLにあるので、詳細はこれらを参考にしてください。

id:winebarrel

回答ありがとうございます。

面白いですね! > mmap()

知らない関数だったので勉強になりました!

2008/06/08 17:54:57
  • id:Bookmarker
    >>
    C言語じゃないですが、Rubyなら、FileもStringIOも同じインターフェースで扱えますよね?
    そんな感じで「fprintfを使っているけど、実はメモリに出力している」というようなことができないかな…と。
    <<

    C++ なら標準で iostream がありますが、どうしても C でないと駄目なんでしょうか?
  • id:ahirusan
    ファイルもメモリもシームレスに扱う例として、「共用メモリ」をご参照下さい。
  • id:winebarrel
    >Bookmarkerさん
    コメントありがとうございます。
    一部でC++を使うというのは、確かにアリかもです。

    >ahirusanさん
    コメントありがとうございます。
    「共用メモリ」で調べてみたいと思います。
  • id:longicorn
    LinuxでGNU拡張でよければfmemopen(3)、open_memstream(3)で出来るみたいです。
  • id:winebarrel
    >longicornさん
    まさにコレ!というような関数です。
    コメントありがとうございます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません