LINUX.ORG.RU

pointer on the stack

 ,


1

3

Всем привет. Есть такой кусок Сишного кода:

#include <stdio.h>

void reset(int *x)
{
    x=0;
}

int main()
{
    int x=1;
    reset(&x);
    printf("x is now 0.\n");
    return 0;
}

на первом фрейме получаю такое:

   0x0000000000400539 <+0>:	push   %rbp
   0x000000000040053a <+1>:	mov    %rsp,%rbp
   0x000000000040053d <+4>:	sub    $0x10,%rsp
=> 0x0000000000400541 <+8>:	movl   $0x1,-0x4(%rbp)
   0x0000000000400548 <+15>:	lea    -0x4(%rbp),%rax
   0x000000000040054c <+19>:	mov    %rax,%rdi
   0x000000000040054f <+22>:	callq  0x400526 <reset>

присваиваем x 1 (очевидно):

x/d $rbp-4
0x7fffffffdabc:	1
в %rdi находится адрес x
p/x $rdi
$3 = 0x7fffffffdabc
далее... на втором фрейме (вызванном reset):
   0x0000000000400526 <+0>:	push   %rbp
   0x0000000000400527 <+1>:	mov    %rsp,%rbp
   0x000000000040052a <+4>:	mov    %rdi,-0x8(%rbp)
=> 0x000000000040052e <+8>:	movq   $0x0,-0x8(%rbp)
   0x0000000000400536 <+16>:	nop
   0x0000000000400537 <+17>:	pop    %rbp
   0x0000000000400538 <+18>:	retq
у нас сформировался новый стек фрейм и все манипуляции проходят внутри этого фрейма, а потом он уничтожается и «выравнивается» %rbp.

Я не понимаю почему именно так? Я думал, что если x = 0 внутри reset(), то по сути он и должен указывать на 0x0 после выхода из reset().


x в reset() указывает на x в main() и при этом является отдельной переменной. Можно менять её, а можно менять то, на что она указывает, но для этого её нужно разименовать сначала (*x = 0;).

xaizek ★★★★★ ()

Лень разгребать неправильный асм. Что ты хочешь-то вообще, изменить значение по указателю или сам указатель?

vazgen05 ★★ ()
Ответ на: комментарий от vazgen05

Лень разгребать неправильный асм.

Простите, что значит «неправильный» асм? Какой правильный тогда?

Что ты хочешь-то вообще, изменить значение по указателю или сам указатель?

Я ожидал, что изменится сам указатель на 0x0

ubik ()
Ответ на: комментарий от ubik

У тебя в x, внутри функции reset находится адрес переменной x из функции main. Этот адрес записан в локальную переменную. Если ты хочешь изменить значение переменной x в main - надо писать *x = 0.

Y ★★ ()
Последнее исправление: Y (всего исправлений: 2)
Ответ на: комментарий от ubik

Какой правильный тогда?

Ну с интеловским синтаксисом же.

Я ожидал, что изменится сам указатель на 0x0

Короче ты изменил копию указателя, в следующий раз передавай указатель на указатель в такой ситуации.

vazgen05 ★★ ()
Ответ на: комментарий от Y

У тебя в x, внутри функции reset находится адрес переменной x из функции main.

Да, я в курсе. Поэтому и возник вопрос.

Этот адрес записан в локальную переменную.

Простите, но я, видимо, тупой :-( Ткните носом где эта локальная переменная?

ubik ()
Ответ на: комментарий от vazgen05

Ну с интеловским синтаксисом же.

Не, это не ко мне.

Короче ты изменил копию указателя, в следующий раз передавай указатель на указатель в такой ситуации.

Да и так это вижу из выхлопа. Но я ожидал совсем другого :-(

ubik ()
Ответ на: комментарий от ubik

Ткните носом где эта локальная переменная?

int *x

Локальная переменная типа «указатель на int».

Vovka-Korovka ★★★★★ ()
Ответ на: комментарий от Y

Спасибо, увидел :)

10	     int x = 1;
(gdb) n
11	     reset(&x);
(gdb) ptype x
type = int
(gdb) p &x
$1 = (int *) 0x7fffffffdabc
(gdb) n

Breakpoint 1, reset (x=0x7fffffffdabc) at pointer_on_stack.c:5
5	     x = 0;
(gdb) ptype x
type = int *
(gdb) p &x
$2 = (int **) 0x7fffffffda98
Спасибо за разъяснение

ubik ()
void reset(int *x)
{
    x=0;
}


vs

void reset(int** x)
{
    (*x) = 0;
}

trex6 ★★★★★ ()
Последнее исправление: trex6 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.