|
|
|
ホーム
全記事一覧
<< 前の記事
次の記事 >>
|
|
|
| |
| | 2008/10/07 11:45||▲
|
|
| mem〜系の関数が続いていますが、今回はメモリブロックの比較を行うmemcmp関数です。strcmp関数とはループの終了条件が異なるだけですが、strcmp関数では、(必ず存在するはずの)ナル文字を比較対象とすることができたのに対して、memcmp関数では、最後の要素を1つ越えたところをアクセスすることができません。
例えば、strcmp関数と同じように書くなら、
int memcmp(const void *s1, const void *s2, size_t n) { register const unsigned char *ss1, *ss2, *t; for (ss1 = s1, ss2 = s2, t = ss2 + n; *ss1 == *ss2 && ss2 != t; ss1++, ss2++) ; return *ss1 - *ss2; }
となるわけですが、これだと必ずメモリブロックを外れたところをアクセスしてしまうため、動作が未定義になります。では、
for (ss1 = s1, ss2 = s2, t = ss2 + n - 1; ss2 != t && *ss1 == *ss2;
とすればよい気もしますが、ポインタは配列の「最後の」要素を1つ越えたところを指すことはできても、「最初の」要素の1つ前を指すことはできません(未定義の動作になります)。
というわけで、今回は次のように記述しました。
#include <stddef.h>
int memcmp(const void *s1, const void *s2, size_t n) { register const unsigned char *ss1, *ss2, *t; int result = 0; for (ss1 = s1, ss2 = s2, t = ss2 + n; ss2 != t && (result = *ss1 - *ss2) == 0; ss1++, ss2++) ; return result; }
これで、とりあえず上で挙げた問題はクリアできたと思います。また、効率的にもさほど問題なさそうです。 実際にはここまでシビアに考えなくても動作する気もしますが、他の処理系に移植するときのことなどを考えると、未定義の動作は避けておいた方が無難でしょう。
| | 2006/04/02 10:19|文字列操作|TB:0|CM:2|▲
|
| |
コメント
|
ついでにこちらも指摘。 最初の二つのコードは未定義動作が含まれているから避けた方がいいのではなく、(未定義動作に関係なく)間違った値を返すことがある。 例 #define FOO "_ABABC" memcmp(FOO+1, FOO+3, 2); memcmp(FOO+1, FOO+2, 0);
|
マイケル #-|2006/04/13(木) 23:20 [ 編集 ]
|
ご指摘ありがとうございます。
> memcmp(FOO+1, FOO+3, 2);
こちらは確かにダメですね。
> memcmp(FOO+1, FOO+2, 0);
こちらは、期待通りの値(0)だと思うのですが、何か勘違いしていますか?
|
たかぎ #ftr86F3A|2006/04/13(木) 23:40 [ 編集 ]
| |
コメントの投稿
| |
|
| |
トラックバック
|
トラックバックURLはこちら
http://libc.blog47.fc2.com/tb.php/40-484b59e8
|
| |
|
|
ホーム
全記事一覧
<< 前の記事
次の記事 >>
|
| |
|
|