2017/02/05

[c/c++]mallocと代入の狭間で

可変長のバッファを作ろうとした。
Cなので、バッファ長も一緒に管理したいので、ありがちな構造体にした。

struct {
  uint8_t   len;
  uint8_t   *buf;
};

まあ、先頭アドレスとサイズがわかればよいので、こうすることが多いだろう。

 

さっきまで、malloc()して可変のバッファを作っていたのだが、ときどきソースコードに埋め込むバッファも使うことがあった。

const uint8_t DATA[] = {
  0xaa, 0xbb, ....
};

値を変更する予定がないので、constを付ける。
付けなかったら、初期値ありのRAMデータになるので、ROMにもRAMにもメモリがいるようになるので、constは付けておきたいところ。

 

が、constポインタのものを非constポインタに代入するというのは、やはりよろしくない。
では、これをwarningするのをキャストで回避すべきか?
そこは悩ましいところだ。
今は自分で分かって実装しているから良いものの、何か事情が変わってしまうと、安全では無くなるかもしれない。

じゃあ放置するか?
そうすると、warningがうっとうしい。
警告はしてほしいけど、今は私が分かっているから警告してほしくない、という、コンパイラには理解できない状況だ。
もし、コンパイラがスルーすると、タイミングによっては「なんで警告しないんだ!」と私が怒るかもしれない。

 

では、構造体の方をconstポインタにすれば良いかというと、そういうわけでもない。
今度はfree()の方で警告されてしまう。
free()自体はポインタ先を書き換えることはないのだろうが、free()するのはmalloc()したところであり、malloc()はconstポインタを返さないので、free()の引数がconstポインタなのはおかしい、ということか。
まあ、メモリを解放してほしいのに、constもなにもあったもんじゃなかろう。


まだ、これについて私の中で解決ができていない。
標準関数を優先して、自分では書き換えないように意識し、constポインタを非constポインタに置き換えて使う、というところか。

回避しているだけよねぇ。。。
でも、私が使う場合にはコンパイルレベルで解決してほしいところなので、こうなってしまいそうに思う。
RAMに空きがあっても、crtなどで初期値をRAMに転送する、などと思ってしまうと、実装の危険があったとしてもキャストしてしまいそうだ。
だって、ROMに書込もうとしたら、OSがあっても無くても、だいたい教えてくれるだろう?

typedef struct {
  uint8_t len;
  uint8_t *buf;
} buf_t;

const uint8_t DATA[] = { 0, 1, 2 };
const buf_t buf = { sizeof(DATA), (uint8_t *)DATA };
buf.buf[0] = 5;

Linuxだと、このくらいは動いてしまうし、Segmentation Faultなどが発生しないのだ。
まあ、文句は言えないのだけど、定数値がコード領域に置かれて、コード領域へのメモリ書込みで例外が発生するのだったら、実行時に例外が発生するかと思ったのだ。


構造体の構成は同じで、ポインタにだけconstをつけた。

struct {
    uint8_t len;
    const uint8_t *buf;
};

そして、値を変更しない関数はそっちを引数に取るようにした。
constが付いていないデータを使いたいなら、こっちの構造体でキャストして使う。
キャストで回避するしかないのだが、constが付く方にキャストするのだったら、まだよいのではなかろうか。

 

だいたい、メンバにポインタを含んだ構造体にconstを付けても、そのメンバがconstになるわけではないから、もうこういう手段しかないような気がする。
しかし、構造体のメンバが構造体で、そっちにもポインタがあったらどんどんと連鎖していってしまう。。。

かといって、自動的にconstが内部メンバに波及してしまうという言語仕様になってしまうと、それはそれで自由度がなくなる。
案外、gcc拡張とかで「波及的const」なんてものがあるのかもしれん。ないか。

__attribute__(const)とか__attribute__(pure)で変更しないことを表せるかと思ったが、関数内で引数の構造体メンバが指している先を書き換えてもエラーにならないし、実行しても動いた。
単に最適化だけの話か。
結局、運用でカバーしよう、で終わってしまいそうな気がする。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。