Несмотря на то, что стандарт C явно признает возможность того, что адрес, который указывает «только что прошел» один объект, может по совпадению совпадать с адресом, который указывает «на» другой неродственный объект, кажется, что и gcc, и clang работают в предположении что ни один указатель, указывающий, что он указывает только за одним объектом, не может указывать на другой, о чем свидетельствует пример:
#include <stdio.h>
int x[1],y[1];
int test1(int *p)
{
y[0] = 1;
if (p==x+1)
*p = 2; // Note that assignment is to *p and not to x[1] !!!
return y[0];
}
int test2(int *p)
{
x[0] = 1;
if (p==y+1)
*p = 2; // Note that assignment is to *p and not to y[1] !!!
return x[0];
}
int (*volatile test1a)(int *p) = test1;
int (*volatile test2a)(int *p) = test2;
int main(void) {
int q;
printf("%llX\n",(unsigned long long)y - (unsigned long long)x);
q = test1a(y);
printf(">> %d %d\n", y[0], q);
q = test2a(x);
printf(">> %d %d\n", x[0], q);
return 0;
}
При моем чтении Стандарта действительные выходные данные этой программы в строках, помеченных >>
, будут либо >> 1 1
, либо >> 2 2
, но gcc для идеальных выходных данных >> 2 1
для одной из строк и из того, что я может сказать, что код, сгенерированный clang, подойдет и для другого.
Мне хорошо известно, что тот факт, что p
сравнивается равным x[1]
, не означает, что последнее выражение может использоваться для доступа к тому же объекту, что и *p
(или к любому объекту вообще, в этом отношении) , но я ничего не знаю в Стандарте, который запрещал бы вычисление x+1
или сравнение между полученным указателем и p
. Я также не знаю ничего, что могло бы сделать такое сравнение непригодным для использования p
для доступа к объекту, адрес которого он содержит.
Имеется ли какое-либо правдоподобное прочтение какой-либо опубликованной или черновой версии стандарта C, в соответствии с которой приведенный выше код вызывает неопределенное поведение, или в соответствии с которой возвращаемые значения из test1
и test2
не потребуются для совпадения с окончательными значениями y[0]
или x[0]
, соответственно, или оптимизаторы в clang и gcc предназначены для обработки диалекта, который не является опубликованной или черновой версией стандарта?
PS - из стандартной тяги N1570 6.5.9p6:
6 Два указателя сравниваются равными, если и только если оба указателя равны нулю, оба указателя на
тот же объект (включая указатель на объект и подобъект в его начале) или функцию,
оба являются указателями на один за последним элементом одного и того же объекта массива, или один является указателем
один за концом одного объекта массива, а другой - указатель на начало другого
объект массива, который происходит сразу же после первого объекта массива в адресе
пространство.
Стандарт никоим образом не подразумевает, что x[]
должен следовать y[]
, и наоборот, но, похоже, явно предусматривает возможность того, что указатель, указывающий сразу за x
, может быть сопоставлен с y
и наблюдается равным.