请教结构体指针打印的问题?谢谢!

StoneBBS 2013-07-22 09:40:50

typedef struct _test_B_s {
unsigned int u32_a;
unsigned int u32_b;
}test_B_t;

int main(int argc, char *argv[])
{
test_B_t st_a;
memset(&st_a, 0, sizeof(st_a));
st_a.u32_a = 0xaaaa0000;
st_a.u32_b = 0x0000bbbb;
test_B_t *pst = &st_a;

printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst);
return 0;
}

打印输出:


请教:代码中打印那一行里面的那2个pst的值为什么不同?
腰包不鼓,小小积分奉上而已,谢谢!

...全文
522 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
大漠孤鸿 2013-07-23
  • 打赏
  • 举报
回复
上面第五次push写错了。 printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst); 汇编代码如下: 00401081 mov eax,dword ptr [ebp-0Ch] 00401084 push eax 00401085 mov ecx,dword ptr [ebp-0Ch] 00401088 mov edx,dword ptr [ecx+4] 0040108B push edx 0040108C mov eax,dword ptr [ecx] 0040108E push eax 0040108F mov ecx,dword ptr [ebp-0Ch] 00401092 push ecx 00401093 push offset string "pst:0x%08x, pst[0]:0x%08x, pst:0"... (0042201c) 00401098 call printf (00401140) 0040109D add esp,14h printf函数4个参数,push了5次。 第一次:pst 第二次:0x0000BBBB 第三次:0xAAAA0000 第四次:pst 第五次:"pst:0x%08x, pst[0]:0x%08x, pst:0" 怎么会是五次呢?
大漠孤鸿 2013-07-23
  • 打赏
  • 举报
回复
printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst); 汇编代码如下: 00401081 mov eax,dword ptr [ebp-0Ch] 00401084 push eax 00401085 mov ecx,dword ptr [ebp-0Ch] 00401088 mov edx,dword ptr [ecx+4] 0040108B push edx 0040108C mov eax,dword ptr [ecx] 0040108E push eax 0040108F mov ecx,dword ptr [ebp-0Ch] 00401092 push ecx 00401093 push offset string "pst:0x%08x, pst[0]:0x%08x, pst:0"... (0042201c) 00401098 call printf (00401140) 0040109D add esp,14h printf函数4个参数,push了5次。 第一次:pst 第二次:0x0000BBBB 第三次:0xAAAA0000 第四次:pst 第五次:pst 怎么会是五次呢?
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 5 楼 nbabn 的回复:
[quote=引用 3 楼 StoneBBS 的回复:] 压栈的顺序不是就是定义局部变量的先后顺序么?代码里先定义结构体变量st_a,然后才是定义结构体指针变量pst,所以压栈顺序就是像你说的那样,不知对不对。
函数内的成员空间不是压栈来获取的,在函数调用之初,只要一条指令sub esp - n就在栈上分配好这个函数体内局部变量要使用的空间了。这也就是在栈上分配空间比在堆上分配空间效率高的原因了。[/quote] 噢,我原来想错了。在linux里面函数调用时,其参数的压栈顺序也是从右往左的。 发生如你所说的压栈方式会不会跟printf的实现有关?
nbabn 2013-07-23
  • 打赏
  • 举报
回复
引用 3 楼 StoneBBS 的回复:
压栈的顺序不是就是定义局部变量的先后顺序么?代码里先定义结构体变量st_a,然后才是定义结构体指针变量pst,所以压栈顺序就是像你说的那样,不知对不对。
函数内的成员空间不是压栈来获取的,在函数调用之初,只要一条指令sub esp - n就在栈上分配好这个函数体内局部变量要使用的空间了。这也就是在栈上分配空间比在堆上分配空间效率高的原因了。
nbabn 2013-07-23
  • 打赏
  • 举报
回复
压栈的顺序是函数调用参数传递的顺序,VC6是按参数列表从右往左的顺序入栈。
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 2 楼 nbabn 的回复:
mov ecx,dword ptr [ebp-18h] mov edx,dword ptr [ecx+4] push edx mov eax,dword ptr [ecx] push eax mov ecx,dword ptr [ebp-18h] push ecx push offset string "......" call printf () VC6下编译成这样了,先压栈的是pst+4,即pst.u32_b,再压栈pst.u32_a,最后压栈的是pst,不明白怎么编译成这样了,谁来解释下。
压栈的顺序不是就是定义局部变量的先后顺序么?代码里先定义结构体变量st_a,然后才是定义结构体指针变量pst,所以压栈顺序就是像你说的那样,不知对不对。 附上Ubuntu Linux的反汇编:

common_test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 e4 f0                and    $0xfffffff0,%esp
   6:   83 ec 30                sub    $0x30,%esp
   9:   c7 44 24 28 00 00 aa    movl   $0xaaaa0000,0x28(%esp)
  10:   aa
  11:   8b 54 24 28             mov    0x28(%esp),%edx
  15:   8d 44 24 28             lea    0x28(%esp),%eax
  19:   c7 44 24 2c bb bb 00    movl   $0xbbbb,0x2c(%esp)
  20:   00
  21:   8b 4c 24 2c             mov    0x2c(%esp),%ecx
  25:   89 44 24 14             mov    %eax,0x14(%esp)
  29:   89 44 24 08             mov    %eax,0x8(%esp)
  2d:   89 54 24 0c             mov    %edx,0xc(%esp)
  31:   89 4c 24 10             mov    %ecx,0x10(%esp)
  35:   c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
  3c:   00
  3d:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)
  44:   e8 fc ff ff ff          call   45 <main+0x45>
  49:   31 c0                   xor    %eax,%eax
  4b:   c9                      leave
  4c:   c3                      ret

nbabn 2013-07-23
  • 打赏
  • 举报
回复
mov ecx,dword ptr [ebp-18h] mov edx,dword ptr [ecx+4] push edx mov eax,dword ptr [ecx] push eax mov ecx,dword ptr [ebp-18h] push ecx push offset string "......" call printf () VC6下编译成这样了,先压栈的是pst+4,即pst.u32_b,再压栈pst.u32_a,最后压栈的是pst,不明白怎么编译成这样了,谁来解释下。
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 18 楼 StoneBBS 的回复:
我打印的结果不对有可能跟我目前的环境有关。谢谢ak47_wz和liyanfasd的热心帮助!结帖。
不好意思,感谢修正如下: 谢谢ak47_wz和liyanfasd及nbabn的热心帮助!
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
我打印的结果不对有可能跟我目前的环境有关。谢谢ak47_wz和liyanfasd的热心帮助!结帖。
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 16 楼 ak47_wz 的回复:
我的环境下 打印出来的是相同的. 环境是 ubuntu 12.04 ,编译器gcc 4.6.3 不知道你的环境是什么情况.
不会吧!我的版本是: 一、 ^_^[root@stone:/mnt/hgfs/share_/safer/common_test/src]#lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 10.04.3 LTS Release: 10.04 Codename: lucid 二、 ^_^[root@stone:/mnt/hgfs/share_/safer/common_test/src]#cat /proc/version Linux version 2.6.32-33-generic (buildd@palmer) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) ) #71-Ubuntu SMP Wed Jul 20 17:30:40 UTC 2011
水平不流 2013-07-23
  • 打赏
  • 举报
回复
我的环境下 打印出来的是相同的. 环境是 ubuntu 12.04 ,编译器gcc 4.6.3 不知道你的环境是什么情况.
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 10 楼 ak47_wz 的回复:
倘若你把 pst[0],改成pst->u32_a,一切就回到了原本预料的情况。

#include<stdio.h>

typedef struct _test_B_s {
    unsigned int u32_a;
    unsigned int u32_b;
}test_B_t;
  
int main(int argc, char *argv[])
{ 
    test_B_t st_a;
    memset(&st_a, 0, sizeof(st_a));
    st_a.u32_a = 0xaaaa0000;
    st_a.u32_b = 0x0000bbbb;
    test_B_t *pst = &st_a;
     
    printf("pst:0x%08x, pst[0]:0x%08x,pst:0x%08x\n", pst, pst->u32_a,pst);
    return 0;
}


说明我刚才的理解是正确的。。。
这个我原来就发现了,确实就是因为打印pst[0]导致的。
StoneBBS 2013-07-23
  • 打赏
  • 举报
回复
引用 9 楼 ak47_wz 的回复:
第三个参数,即使你随便写,不写pst一样会打印出b的值的。以前代码就是为证。

#include<stdio.h>

typedef struct _test_B_s {
    unsigned int u32_a;
    unsigned int u32_b;
}test_B_t;
  
int main(int argc, char *argv[])
{ 
    test_B_t st_a;
    memset(&st_a, 0, sizeof(st_a));
    st_a.u32_a = 0xaaaa0000;
    st_a.u32_b = 0x0000bbbb;
    test_B_t *pst = &st_a;
     
    printf("pst:0x%08x, pst[0]:0x%08x,pst:0x%08x,pst:0x%08x\n", pst, pst[0],pst[2],pst);
    return 0;
}

说明一个问题是,printf在读取结构体时,把整个结构体读入到了缓存中。但是第一个只打印出a,缓存中仍然存在着b的数据,于是下一个打印出b,不管是什么参数。此时如果在打印出pst,可以发现,又回到正常情况,打印出pst地址。 我是这么理解的。不知道对不对。
按照你的理解,道理上第2个pst打印的值应该是正确了的啊,但是我发现那2个pst打印的值不相同哦! 输出打印: pst:0xbfe4f488, pst[0]:0xaaaa0000, pst:0x0000bbbb, pst:0xbfe4f518
水平不流 2013-07-23
  • 打赏
  • 举报
回复
引用 12 楼 liyanfasd 的回复:
[quote=引用 11 楼 ak47_wz 的回复:] 压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。 [quote=引用 8 楼 liyanfasd 的回复:] 上面第五次push写错了。 printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst); 汇编代码如下: 00401081 mov eax,dword ptr [ebp-0Ch] 00401084 push eax 00401085 mov ecx,dword ptr [ebp-0Ch] 00401088 mov edx,dword ptr [ecx+4] 0040108B push edx 0040108C mov eax,dword ptr [ecx] 0040108E push eax 0040108F mov ecx,dword ptr [ebp-0Ch] 00401092 push ecx 00401093 push offset string "pst:0x%08x, pst[0]:0x%08x, pst:0"... (0042201c) 00401098 call printf (00401140) 0040109D add esp,14h printf函数4个参数,push了5次。 第一次:pst 第二次:0x0000BBBB 第三次:0xAAAA0000 第四次:pst 第五次:"pst:0x%08x, pst[0]:0x%08x, pst:0" 怎么会是五次呢?
压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。 [/quote] 结构体压栈时,对结构体成员压栈的顺序有规定吗?[/quote] 这个我不太清楚,不过看汇编代码的话,应该执行方式都是一样的,.一样存在着顺序.从高地址到低地址,或者从低地址到高地址.这个我感觉没太大必要去深究,这具体编译器会有不同的实现.
大漠孤鸿 2013-07-23
  • 打赏
  • 举报
回复
引用 11 楼 ak47_wz 的回复:
压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。 [quote=引用 8 楼 liyanfasd 的回复:] 上面第五次push写错了。 printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst); 汇编代码如下: 00401081 mov eax,dword ptr [ebp-0Ch] 00401084 push eax 00401085 mov ecx,dword ptr [ebp-0Ch] 00401088 mov edx,dword ptr [ecx+4] 0040108B push edx 0040108C mov eax,dword ptr [ecx] 0040108E push eax 0040108F mov ecx,dword ptr [ebp-0Ch] 00401092 push ecx 00401093 push offset string "pst:0x%08x, pst[0]:0x%08x, pst:0"... (0042201c) 00401098 call printf (00401140) 0040109D add esp,14h printf函数4个参数,push了5次。 第一次:pst 第二次:0x0000BBBB 第三次:0xAAAA0000 第四次:pst 第五次:"pst:0x%08x, pst[0]:0x%08x, pst:0" 怎么会是五次呢?
压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。 [/quote] 结构体压栈时,对结构体成员压栈的顺序有规定吗?
水平不流 2013-07-23
  • 打赏
  • 举报
回复
压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。
引用 8 楼 liyanfasd 的回复:
上面第五次push写错了。 printf("pst:0x%08x, pst[0]:0x%08x, pst:0x%08x\n", pst, pst[0], pst); 汇编代码如下: 00401081 mov eax,dword ptr [ebp-0Ch] 00401084 push eax 00401085 mov ecx,dword ptr [ebp-0Ch] 00401088 mov edx,dword ptr [ecx+4] 0040108B push edx 0040108C mov eax,dword ptr [ecx] 0040108E push eax 0040108F mov ecx,dword ptr [ebp-0Ch] 00401092 push ecx 00401093 push offset string "pst:0x%08x, pst[0]:0x%08x, pst:0"... (0042201c) 00401098 call printf (00401140) 0040109D add esp,14h printf函数4个参数,push了5次。 第一次:pst 第二次:0x0000BBBB 第三次:0xAAAA0000 第四次:pst 第五次:"pst:0x%08x, pst[0]:0x%08x, pst:0" 怎么会是五次呢?
压栈5次主要是因为,pst[0],读取了整个结构体。 也就可以理解为什么是压栈5次了。
水平不流 2013-07-23
  • 打赏
  • 举报
回复
倘若你把 pst[0],改成pst->u32_a,一切就回到了原本预料的情况。

#include<stdio.h>

typedef struct _test_B_s {
    unsigned int u32_a;
    unsigned int u32_b;
}test_B_t;
  
int main(int argc, char *argv[])
{ 
    test_B_t st_a;
    memset(&st_a, 0, sizeof(st_a));
    st_a.u32_a = 0xaaaa0000;
    st_a.u32_b = 0x0000bbbb;
    test_B_t *pst = &st_a;
     
    printf("pst:0x%08x, pst[0]:0x%08x,pst:0x%08x\n", pst, pst->u32_a,pst);
    return 0;
}


说明我刚才的理解是正确的。。。
水平不流 2013-07-23
  • 打赏
  • 举报
回复
第三个参数,即使你随便写,不写pst一样会打印出b的值的。以前代码就是为证。

#include<stdio.h>

typedef struct _test_B_s {
    unsigned int u32_a;
    unsigned int u32_b;
}test_B_t;
  
int main(int argc, char *argv[])
{ 
    test_B_t st_a;
    memset(&st_a, 0, sizeof(st_a));
    st_a.u32_a = 0xaaaa0000;
    st_a.u32_b = 0x0000bbbb;
    test_B_t *pst = &st_a;
     
    printf("pst:0x%08x, pst[0]:0x%08x,pst:0x%08x,pst:0x%08x\n", pst, pst[0],pst[2],pst);
    return 0;
}

说明一个问题是,printf在读取结构体时,把整个结构体读入到了缓存中。但是第一个只打印出a,缓存中仍然存在着b的数据,于是下一个打印出b,不管是什么参数。此时如果在打印出pst,可以发现,又回到正常情况,打印出pst地址。 我是这么理解的。不知道对不对。
StoneBBS 2013-07-22
  • 打赏
  • 举报
回复
自己顶一下,别沉。

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧