Непонятное поведение кода C с объявлением теневой структуры - PullRequest
1 голос
/ 08 июня 2019

Рассмотрим следующий код C:

#include <stdio.h>

typedef struct {
    int a;
} TestType;

int main(){
    int an_int;
    TestType test;
    // printf("%d\n",test.a);
    {
        TestType test;
        test.a = 777;
        printf("offset: %lld\n", &test.a - &an_int); // maybe 2?
    }
    printf("%d\n", test.a);                        // should be garbage
    printf("offset: %lld\n", &test.a - &an_int);     // maybe 1?    
}

Я объявляю TestType test, затем запускаю область и объявляю еще один TestType test, следящий за первым. Ожидаемый вывод оператора print в конце - это то, что было в стеке. Скомпилировав с gcc -o stack-allocate-weird stack-allocate-weird.c и запустив, я получаю вывод:

offset: 1
777
offset: 1

Так что эти два места одинаковы. Кроме того, valgrind ./stack-allocate-weird не сообщает об ошибках. Раскомментирование первого оператора print дает ожидаемый результат:

-771776240
offset: 2
-771776240
offset: 1

Если вместо struct TestType я просто объявляю int, код работает так, как ожидалось (последний оператор print печатает мусор).

Я поместил код на сервер, скомпилировал его и получил:

offset: -2
0
offset: -1

Что тоже хорошо выглядит (полагаю, стек идет в противоположном направлении?). С другой стороны, перенос бинарного файла, скомпилированного на моем компьютере, на сервер дал исходный неверный вывод:

offset: 1
777
offset: 1 

Это известная ошибка с gcc?

gcc -v на моем компьютере говорит (куча других вещей и):

gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)    

На сервере написано:

gcc version 8.3.1 20190223 (Red Hat 8.3.1-2) (GCC)

Так, может быть, это было исправлено где-то посередине?

1 Ответ

3 голосов
/ 08 июня 2019

Я не думаю, что это ошибка в GCC.Компилятор задерживает выделение внешнего TestType test до тех пор, пока оно не понадобится.И это в вашем втором printf() в строке 16. Внутренний TestType test помещается со смещением 1, как вы наблюдали, пока его область не будет закрыта, и его память снова не освободится.Теперь внешний нужен и занимает то же самое пространство, давая вам значение внутреннего и такое же смещение.

...