(gdb)print指针和printf(“%p”,pointer)提供不同的地址

时间:2018-06-22 14:14:43

标签: c gdb

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上均可成功运行。

2 个答案:

答案 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的行为符合预期。 (此版本更清晰)