mallocなどで確保した任意のメモリ領域をFILE構造体、またはファイルディスクリプタとして扱う方法はないでしょうか?
OSに依存した方法でもかまわないです。
>mallocなどで確保した任意のメモリ領域をFILE構造体、
>またはファイルディスクリプタとして扱う方法はないでしょうか?
なぜ、そのようなことをしたいのか、まず動機を明らかにした方がよいでしょう。
そもそもFILE構造体や配下の情報について、構造を意識する必要は通常はありません。
(意識しなくても良いように/させることの無いように設計されています。)
FILE構造体配下の定義はコンパイラが提供するヘッダファイルをみればわかりますが、
別のデータ(関数、構造体、ストリームバッファなど)へのポインタだらけです。
ナンセンスな話ですが、仮に、FILE構造体をmallocして与えることができても、
それら別データの領域確保もやらねばなりませんし、IOするたびにどこかの領域を
開放・再確保しなければならないのかもしれません。
しかも環境依存であるので、そういう部分をさわるプログラムはCのバージョンが
変わっただけで使い物にならなくなる可能性が高いです。
大抵のOSではファイルアクセス用のシステムルーチンやライブラリが限定されていて
そのOS上で動く言語が提供するファイルアクセス機能は、それらのシステムルーチンを
呼び出す形で実装されます。
CのファイルIO関数群も、それらのシステムルーチンを呼び出すことになるわけですが、
環境によっては、そちらを呼び出す方法が正式に提供されていることがあります。
当然その場合、FILE構造体を使うアクセス手順とは異なるプログラミングが必要。
管理領域を自前で用意するルールであるいうケースも普通です。
回答ありがとうございます。
上記のコメントの通り、やりたいことはメモリ/ファイルを意識しないような操作です。
分かりづらくて、すいません…
すでに#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 したらどうでしょうか。
回答ありがとうございます。
標準ライブラリを使うのは、やっぱり難しそうですね…
1.もし本当にFILE構造体を使いたかったら普段使っているライブラリを修正すれば可能かもしれないです。
あとは関数をフックしてやるとか。
2.ファイルディスクリプタは所詮int型で実体はカーネルが管理しているのでドライバを書く等すれば可能かも。
あとはカーネルを改造してやって、新規関数を作れば可能でしょう。
3.そこまでやる気がないのであれば、自前でopen()等をラップした関数を作成してやって、
自前のmalloc()で作ったデータにもその関数を通して使うように工夫すれば出きるでしょう。
4.番外編でsystem()を使ってRubyを呼べば可能ですよ。
まあ、冗談ですけど。
結局真面目にやるのであれば1,2の方法でしょうけどOSや言語の下位の部分が担当している部分に触らないとどうしようもないです。
現実解としては3の方法になるでしょう。
しかしその前に少し考えてみてください。
そもそも、そのような設計になるのが問題です。C++等のOOPを使えばこの辺は少しはマシになるかと。
5.おまけ。
その他ヒントになるかもしれない関数リストの一部分を挙げておきます。
fdopen(),freopen(),dup(),dup2(),mmap(),mknod()
回答ありがとうございます。
>そもそも、そのような設計になるのが問題です。
そうですねー。
そもそも、ファイルしか扱えないライブラリを、簡単にメモリも扱えるようにできないか、というのが根本的な動機だったのですが、そんな使い方するなってことですよね…
OSの機能を使えば
どちらでも可能です。
前者のファイルをメモリとして読み書きする方法は、 memory mapped file と言います。
memory mapped file を使うには
という関数を使います。
使い方は、どちらも同じです。たとえば mmap()を使って、"file.txt"というファイルに"hogehoge"という文字列を書き込むには、以下のようなコードを書きます。(実際にはopen()とmmap()にはもう少し引数が必要ですが、以下のコードでは省略しています。)
int fd = open("file.txt"); char *p = mmap(fd); sprintf(p, "hogehoge"); munmap(p); close(fp);
動作を説明すると、このコードは
という処理を行っています。
このように memory mapped file を使うと、sprintf()を使っているけど、実はファイルに書き出している、という処理が実現できます。
実際にコンパイル&実行できるソースコードが以下のURLにあるので、詳細はこれらを参考にしてください。
回答ありがとうございます。
面白いですね! > mmap()
知らない関数だったので勉強になりました!
すいません。確かに説明不足ですね。
C言語で、ファイルでもメモリでもシームレスに扱う方法がないかなーと思って質問しました。
例えば、read(2)だったら、ファイルでもソケットでもシームレス(な感じ)に扱えますよね?
C言語じゃないですが、Rubyなら、FileもStringIOも同じインターフェースで扱えますよね?
そんな感じで「fprintfを使っているけど、実はメモリに出力している」というようなことができないかな…と。
「sprintfを使え」と言われればそれまでなんですが、メモリでもファイルでもシームレスに操作できる方法があれば、教えていただきたいです。