#c
#c
Вопрос:
#include <iostream>
int main(int argc, char *argv[]) {
int x = 3;
int y;
int *px = amp;x;
y = *px--;
*px = 5;
std::cout << "amp;x = " << amp;x << " px = " << px << " amp;px = " << amp;px << "amp;y =" << amp;y; // strange line
std::cout << "x = " << x << " y = " << y << std::endl;
std::cin.get();
}
Когда я использую amp;y в «странной строке», система выводит x = 3, y = 5, это можно объяснить, потому что в реальной стековой памяти адрес x находится в верхнем месте, адрес y — в нижнем месте (адрес y = x’address — 4), поэтому * px = 5 изменяет значение y;
НО! Что-то очень странное происходит, когда я использую y вместо amp;y в «странной строке», x = 3 и y = 3! Что случилось? Кажется, что даже я использую «g -O0», ничего не меняется, так что это не ошибка компилятора, так почему? Картинка следующая:
Комментарии:
1. Здесь вы просто копаетесь в стеке. Это все неопределенное поведение.
2. Не предполагайте, что расположение адреса
x
иy
связаны. Если только вы не пытаетесь понять, как gcc реализует неопределенное поведение. Однако это не нужно.3. Если вы хотите объяснение того, что происходит, вам нужно посмотреть на ассемблерный код. Мы перешли от кодирования более низкого уровня к кодированию более высокого уровня, чтобы избежать подобных странных вещей. Следуйте границам языка, и он будет относиться к вам хорошо.
4.
*px = 5 change y's value
Нет. Это просто вызывает неопределенное поведение . Вместо этого использование другого компилятора может привести к сбою программы, или g может выводить разные числа при компиляции завтра или при выходе следующей версии.5. Вместо того, чтобы пытаться угадать, почему происходит такое поведение, посмотрите на ассемблерный код. Он расскажет вам, почему это происходит. Играть в гольф с 20 угадываниями, пытаясь выяснить неопределенное поведение, — это не то, что нужно делать серьезным пользователям C . Мы просто избегаем неопределенного поведения. Это напоминает мне шутку «Доктор, мне больно, когда я это делаю!». «Тогда не делай этого».
Ответ №1:
В этой строке:
y = *px--;
вы вызываете неопределенное поведение, вычисляя недопустимый указатель. px
указывает на int
, и его нельзя уменьшить. Даже если px
можно было бы уменьшить, разыменовав его:
*px = 5;
не будет разрешено, поскольку оно не указывает на допустимую память.
Программа может делать вообще что угодно, и анализ выходных данных, которые она выдает, не имеет смысла, по крайней мере, в рамках правил языка.
Комментарии:
1. Но я распечатываю amp;x и amp;y, amp;x = 0x65fe1c amp; y = 0x65fe18, разве это не точка px на y?
2. Нет, совсем нет. Нет требования, чтобы что-либо указывало куда угодно. Это именно то, что такое UB.
3. Но все еще не могу объяснить, почему, когда я использую amp;y, он становится x = 3 y = 5, и я не использую никаких ссылок или адресов о y, он становится x = 3 y = 3,