Могут ли два разных объекта с автоматической длительностью хранения сравниваться при сопоставлении адресов? - PullRequest
0 голосов
/ 03 июня 2018

В частности, разрешено ли сравнивать адреса двух автоматических переменных в разных функциях следующим образом:

sink.c

#include <stdio.h>
#include <stdlib.h>

void sink(void *l, void *r) {
    puts(l == r ? "equal" : "not equal");
    exit(0);
}

main.c

typedef struct { char x[32]; } Foo;

void sink(void *l, void *r);

Foo make(void *p) {
    Foo f2;
    sink(&f2, p);
    return f2;
}

int main() {
    Foo f1 = make(&f1);
}

Я ожидал бы, что это напечатает not equal, поскольку f1 и f2 являются различными объектами.С gcc я получаю not equal, но с моей локальной версией clang 3.8 1 , он печатает equal, когда скомпилирован как clang -O1 sink.c main.c 2 .

Разборка make и main ...

0000000000400570 <make>:
  400570:   53                      push   rbx
  400571:   48 89 fb                mov    rbx,rdi
  400574:   e8 d7 ff ff ff          call   400550 <sink>
  400579:   48 89 d8                mov    rax,rbx
  40057c:   5b                      pop    rbx
  40057d:   c3                      ret    
  40057e:   66 90                   xchg   ax,ax

0000000000400580 <main>:
  400580:   48 83 ec 28             sub    rsp,0x28
  400584:   48 8d 7c 24 08          lea    rdi,[rsp+0x8]
  400589:   48 89 fe                mov    rsi,rdi
  40058c:   e8 df ff ff ff          call   400570 <make>
  400591:   31 c0                   xor    eax,eax
  400593:   48 83 c4 28             add    rsp,0x28
  400597:   c3                      ret    

... мы видим, что make, кажется, вообще никогда не создает объект Foo f2, он просто вызываетsink с существующими rdi и rsi (параметры l и r соответственно).Они передаются main и одинаковы: первый, rdi, является скрытым указателем на место, куда следует поместить возвращаемое значение, а второй - &f1, поэтому мы ожидаем, что они будут одинаковыми.


1 Я проверил версии до 7.0 и поведение примерно такое же.

2 Это происходит для -O1, -O2 и -O3, но не -O0, который печатает not equal.

1 Ответ

0 голосов
/ 03 июня 2018

Стандартная часть C11 6.5.9 / 6 гласит:

Два указателя сравниваются равными тогда и только тогда, когда оба являются нулевыми указателями, оба являются указателями на один и тот же объект (включая указатель на объекти подобъект в его начале) или функция, оба являются указателями на один после последнего элемента одного и того же объекта массива, или один - указатель на один после конца одного объекта массива, а другой - указатель на началодругой объект массива, который сразу следует за первым объектом массива в адресном пространстве.

В этом коде не выполняется ни одно из перечисленных условий;&f1 и &f2 являются указателями на разные объекты, и один не является подобъектом другого.

Так что указатели не должны сравниваться одинаково.Сообщение компилятора equal не соответствует.


Примечание: Если у кого-то есть сомнения относительно законности Foo f1 = make(&f1);, , см. Этот вопрос .Это нормально, и время жизни автоматического объекта начинается с предыдущего {.

...