int main(){
int value = 25;
int *pointer = &value;
printf("value = %d\n",value);
printf("pointer = %p\n",pointer);
printf("&pointer = %p\n",&pointer);
当我执行该程序时,它为 value 输出25,为 pointer 显示0xbffff834
,为&pointer 0xbffff830。 >。但是,当我使用GDB调试该程序并键入break 6
(指向行printf("value" = %d",value);
)并键入print pointer
时,GDB会给我结果0xbffff824
。当我键入0xbffff820
时,它也会给我print &pointer
。调试器提供的地址与程序打印的地址不应该相同吗?如果不是必须的话,您能解释为什么吗?当我在调试器中输入x/d pointer
时,它会给我25(顺便说一句是正确的)。我的问题不是pointer
和&pointer
为何不同,这是为什么当我在运行程序时使用相同的指针(在这种情况下,名为pointer
的指针)存储不同的地址。命令./deneme
(程序名称为 deneme ,当我使用gdb调试器调试程序时。我使用命令gcc -g -o deneme deneme.c
编译程序。程序顺便说一下,它在调试器上和./deneme
上均可成功运行。
答案 0 :(得分:2)
首先,回答您的问题:
调试器提供的地址和程序打印的地址不应该相同吗?
答案是肯定的,他们应该这样做。这是合理调试的要求。
但是,在实践中,有时情况可能会出现问题。例如,如果您的程序依赖于未定义的行为,那么您可能会遇到以下情况:编译器做一件事(例如,执行一个分支),而调试器报告了其他事情(打印条件表明它显然不应该这样做)分支)。差异的另一个原因是编译器错误。或优化导致代码显然无序执行(即,您可能会在预期之前或之后看到变量的值更改)。
正如评论者所指出的,这里最有可能发生的是地址空间随机化(“ ASLR”)。这是一项安全功能,通过它可以在运行之间更改内存布局。 gdb默认情况下会禁用此功能,但在大多数系统上,默认情况下会在gdb之外启用该功能。
例如,当我在控制台上尝试程序时,每次运行都会看到不同的指针值:
$ ./q
value = 25
pointer = 0x7ffc7797716c
&pointer = 0x7ffc77977160
$ ./q
value = 25
pointer = 0x7ffd77b8199c
&pointer = 0x7ffd77b81990
因此,重要的是将gdb中的值与gcc中相同运行所打印的值进行比较。这对我来说很好:
(gdb) b 8
Breakpoint 1 at 0x400542: file q.c, line 8.
(gdb) r
Starting program: /tmp/q
value = 25
pointer = 0x7fffffffd8fc
&pointer = 0x7fffffffd8f0
Breakpoint 1, main () at q.c:8
8 }
(gdb) info local
value = 25
pointer = 0x7fffffffd8fc
(gdb) p &pointer
$1 = (int **) 0x7fffffffd8f0
在这里您可以看到值相同。
答案 1 :(得分:0)
edit:Alp,谢谢您的澄清。 关于“为什么同一变量在不同的运行中可能具有不同的地址”,我不知道一个简明的答案,这是我需要做更多研究的地方。
原始答案: 您写了(强调):
...然后输入print pointer ,GDB会给我结果0xbffff8 24 。当我键入print &pointer 时,它还会给我0xbffff8 20 。调试器提供的地址与程序打印的地址不应该相同吗?
关于您的问题,我同意每个人都应该相同。 我无法确定您的问题是否是比较2个不同运行的值(一个独立运行,一个来自gdb内部运行)。正如让·弗朗索瓦·法布尔(Jean-FrançoisFabre)所说,在一次运行中比较地址很重要,因此我们将在此处进行。
您的变量名按原样(它们的重载指针和值)进行了一些讨论,因此这里是一个等效程序。我只是将 v 用于值和 p 而不是指针。 这能准确反映您的工作吗?
$ nl -b a bar.c
1 #include <stdio.h>
2 int main() {
3 int v = 25;
4 int *p = &v;
5 printf("v=%d\n", v);
6 printf("p=%p\n", p);
7 printf("&p=%p\n", &p);
8 }
9
在第8行上设置一个断点并运行程序会产生以下结果:
$ gcc -g bar.c
$ gdb a.out
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
...etc...
Reading symbols from a.out...done.
(gdb) break 8
Breakpoint 1 at 0x400601: file bar.c, line 8.
(gdb) r
Starting program: /home/jgreve/stackoverflow/pointer_basar/a.out
v=25
(i) p=0x7fffffffddfc
(ii) &p=0x7fffffffde00
Breakpoint 1, main () at bar.c:8
8 }
(gdb) print p
(iii) $1 = (int *) 0x7fffffffddfc
(gdb) print &p
(iv) $2 = (int **) 0x7fffffffde00
(gdb) x/d p
(v) 0x7fffffffddfc: 25
(gdb) quit
A debugging session is active.
Inferior 1 [process 10380] will be killed.
Quit anyway? (y or n) y
$
请注意,(i)和(iii)相同,它们都将 v 的地址显示为0x7fffffffdd fc 。
(ii)和(iv)相同,都显示 p 的地址,与&p 相同,如0x7fffffffde 00 。
简而言之,打印&p 并没有为您提供 v 的地址,而是 p 的地址。强>。 由于 v 和 p 是不同的变量,因此必须具有不同的地址。
fwiw,(v)还显示期望的十进制值 25 ,即内存位置0x7fffffffdd fc 的内容(例如 address < strong> v )。
edit:我的原著是一个冗长的例子,谈论内存映射,然后我杀死了它,因为我认为我不理解您的问题。 更仔细地重读该问题使我认为我(大多数)是第一次正确地解决了该问题,并且gdb的行为符合预期。 (此版本更清晰)