2

stpcpy次のバージョンの関数を、restrict修飾されたポインターを引数として内部的に使用するように適応させようとしていますが、修飾子を追加するだけで未定義の動作が発生するかどうかはわかりません。

#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)

char *__stpcpy(char *d, const char *s)
{
        size_t *wd;
        const size_t *ws;

        if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
                for (; (*d=*s) && ((uintptr_t)s & ALIGN); s++, d++);
                if (!*s) return d;
                wd=(void *)d; ws=(const void *)s;
                for (; !HASZERO(*ws); *wd++ = *ws++);
                d=(void *)wd; s=(const void *)ws;
        }
        for (; (*d=*s); s++, d++);

        return d;
}

オブジェクトへのアクセスに関する C99 6.7.3.1 の規則が、アクセスされる個々のオブジェクトのみに関係し、配列全体には関係しないと仮定すると、書き込まれた要素は一度だけアクセスされ、書き込みのためだけにアクセスされるため、問題ないと思います。しかし、私はrestrictこの時点で使用することにかなり不快であり、自分の判断だけに頼りたくありません.

4

1 に答える 1

3

標準に準拠するための唯一の制限は、関数がポインターを介して受け取るオブジェクトを操作するすべてのポインター式は、そのポインターに基づくrestrict必要があるということです。ポインター式が同じ型である必要はありません。その意味で、これらを介してオブジェクトにアクセスすることは、制約違反または UB ではありません。size_t*

ポインターの型が異なるため、変更したオブジェクトの一部の値を読み取る*wdことがエイリアスにならないかどうかはわかりません。*dでも、おっしゃるとおりそんなことはしないので、これは安全なはずです。

ところで、このコードは、必ずしも移植可能ではない 1 つの重要な仮定を行っています。つまり、a の下位ビットは、uintptr_t変換したポインターのアラインメント プロパティを反映しているということです。これはおそらく、日常的に使用するすべてのアーキテクチャに当てはまりますが、標準では保証されていません。C11でさえ、「バイトアドレスの倍数」について何かを言うだけで、それが何であるかを指定するものは何もありません。

于 2012-09-04T07:58:50.837 に答える