int vv[3], *v = &vv[-1];
v[1] = v[2] = v[3] = 0;
または
int *vv = malloc(3 * sizeof(int)), *v = vv - 1;
v[1] = v[2] = v[3] = 0;
のように、配列や malloc した範囲の外を指すアドレス
(この場合 vv - 1)を参照することは、
意図の通りに動くことが保証されているのでしょうか?
神田敏広 <ca...@kgc.co.jp>
<s7f65c3...@xxx.kgc.co.jp>の記事において
ca...@xxx.kgc.co.jpさんは書きました。
candy> C89 の配列またはポインタで、
candy> 例えば引数が 1 から 3 の配列を疑似的に表現しようと、
(snip)
candy> のように、配列や malloc した範囲の外を指すアドレス
candy> (この場合 vv - 1)を参照することは、
candy> 意図の通りに動くことが保証されているのでしょうか?
ほとんどの処理系では意図した通りに動作すると思いますが, C99 の規
格によると undefined behavior です. C89 の規格は持ってないけど,
C89 でもそうじゃなかったかなぁ.
C99 では Appendix J Portability issues の J.2 Undefined behavior
の中に
Addition or subtraction of a pointer into, or just beyond, an
array object and an integer type produces a result that does not
point into, or just beyond, the same array object.
とあります.
int vv[3], *v = &vv[-1];
は
int vv[3], *v = vv+(-1);
と等価 (6.5.3.2 Address and indirection operators の paragraph 3)
で, この vv+(-1) が上の条件にあてはまるから undefined behavior に
なります.
# どうでもいいけど &vv[3] は OK.
--
名古屋大学大学院 情報科学研究科 計算機数理科学専攻
小野 孝男
ta...@hirata.nuee.nagoya-u.ac.jp (Takao Ono) writes:
> C99 では Appendix J Portability issues の J.2 Undefined behavior
> の中に
> Addition or subtraction of a pointer into, or just beyond, an
> array object and an integer type produces a result that does not
> point into, or just beyond, the same array object.
> とあります.
> int vv[3], *v = &vv[-1];
> は
> int vv[3], *v = vv+(-1);
> と等価 (6.5.3.2 Address and indirection operators の paragraph 3)
> で, この vv+(-1) が上の条件にあてはまるから undefined behavior に
> なります.
やはりそうですよねえ……
malloc した領域も array object と考えていいんですよね?
元ネタは
<URL:http://www.numerical-recipes.com/pubdom/nrutil.c.txt>
なんですが。
> # どうでもいいけど &vv[3] は OK.
これが合法的に参照できないと不便でしょうがないので、
どうでもよくありません。
神田敏広 <ca...@kgc.co.jp>
In article <s7f65c3...@xxx.kgc.co.jp>
ca...@xxx.kgc.co.jp writes:
> 例えば引数が 1 から 3 の配列を疑似的に表現しようと、
> int vv[3], *v = &vv[-1];
> v[1] = v[2] = v[3] = 0;
配列の引数じゃなくて添字ね。そういうことなら、これでいいんじゃ
ないですか。
int vv[3+1];
それで、v[0] は使わないことにします。一貫性をもって v[0] を
使わないなら、それで用は足りているはずです。
あと、Cでそういうことをするには、常套手段としては、マクロを
使います。たとえば、
#define v(i) vv[i-1]
としておいて
< v(1) = v(2) = v(3) = 0;
と書くと
< vv[1-1] = vv[2-1] = vv[3-1] = 0;
と展開されます。引算入っていますが、別に最近のコンパイラや
CPUなら遅くはならないと思います。と言った、int *v の間接
より速いとは言いにくいけど、速そうな気もします。
丸い括弧は、Fortran みたいだし。いいんじゃないですか。
\\ 新城 靖 (しんじょう やすし) \\
\\ 筑波大学 電子・情報 \\
> #define v(i) vv[i-1]
> としておいて
> < v(1) = v(2) = v(3) = 0;
> と書くと
> < vv[1-1] = vv[2-1] = vv[3-1] = 0;
> と展開されます。
一応の作法として、
#define v(i) vv[(i)-1]
としたほうが無難かと。
v(x=y) などとされたらたまったものではありません。
========================================================================
飯嶋 浩光 / でるもんた・いいじま http://www.ht.sakura.ne.jp/~delmonta/
IIJIMA Hiromitsu, aka Delmonta mailto:delm...@ht.sakura.ne.jp
> 配列の引数じゃなくて添字ね。
う、なんか書いてて違和感あったのはこれだったのか。
御指摘ありがとうございます。
> int vv[3+1];
>
> それで、v[0] は使わないことにします。一貫性をもって v[0] を
> 使わないなら、それで用は足りているはずです。
まあそうなんですが、別記事にも書きましたように、元ネタは
<URL:http://www.numerical-recipes.com/pubdom/nrutil.c.txt>
で、なにやら数値演算のパッケージの一部らしいのです。
で、オフセットは 1 に限らず(負も含め)任意にしたいみたいですね。
現実には 0 か 1 以外で使うことは、ほぼないでしょうけど。
このコードには matrix() という二次元版もありまして、
オフセットが大きくなると、ムダも大変大きくなると。
> あと、Cでそういうことをするには、常套手段としては、マクロを
> 使います。たとえば、
>
> #define v(i) vv[i-1]
飯島さんの指摘もありますが、 i は (i) でしょう。
<URL:http://www.numerical-recipes.com/news.html>
によると、最新版(売りもの)では
| vectors and matrices are now zero-based!
と自慢しているので、たぶんその類の実装に変えたのだと思います。
> 丸い括弧は、Fortran みたいだし。いいんじゃないですか。
これウケました。すごくいいと思います!!
オフセットを 1 にしたいという要求が、
そもそもはおそらく FORTRAN のコードを使いたいということだと思いますので。
でも配列名もマクロに組み込むと
#define index(v,i)
とかなって見苦しいですね。
LISP みたいでいいか?
神田敏広 <ca...@kgc.co.jp>
In article <s7f3c70...@xxx.kgc.co.jp>
ca...@xxx.kgc.co.jp writes:
> まあそうなんですが、別記事にも書きましたように、元ネタは
> <URL:http://www.numerical-recipes.com/pubdom/nrutil.c.txt>
> で、なにやら数値演算のパッケージの一部らしいのです。
> で、オフセットは 1 に限らず(負も含め)任意にしたいみたいですね。
Pascal みたい。v : array[-128..127] of integerだったかなあ。
あ、Pascal の文法忘れている。
Cでやるなら、こんな感じ。
struct array
{
int lower ;
int upper ;
int data[0];
};
#define ref(a,i) ((a)->data[(i)-(a)->lower])
まあ、せっかくやるなら、添字の範囲チェックもしたいですね。
#define ref(a,i) (((a)->lower <= (i) && (i) < (a)->upper) ? \
((a)->data[(i)-(a)->lower]) : exit(1))
突っ込みがあったので、括弧を増やしてみました。
> でも配列名もマクロに組み込むと
> #define index(v,i)
> とかなって見苦しいですね。
そういう時には、ローカル・マクロ。
struct array *_v;
_v = malloc(sizeof(struct array)+256*sizeof(int));
v->lower = -128 ; _v->upper = 128 ;
#define v(i) ref(_v,(i))
v(10) = 100 ;
#undef v