C语言结构体的学习,以及gdb的调式
- #include <stdio.h>
- #include <string.h>
- #define format "%d\n%s\n%f\n%f\n%f\n"
- typedef struct
- {
- int num;
- int num2;
- } ble_gap_conn_params_t;
- struct student
- {
- int num;
- char name[];
- float score[];
- ble_gap_conn_params_t * p_teacher;
- };
- struct student stru2;
- ble_gap_conn_params_t m_preferred_conn_params
- ={,};
- ble_gap_conn_params_t m_preferred_conn_params1;
- void change( struct student* stu );
- int main()
- {
- struct student stu, p_stu;
- stu.num = ;
- strcpy(stu.name, "Tom");
- stu.score[] = 67.5;
- stu.score[] = ;
- stu.score[] = 78.6;
- stu.p_teacher = &m_preferred_conn_params;
- p_stu = stu;
- printf("p_stu.num = %d\n",p_stu.num);
- change(&stu);
- printf(format, stu.num, stu.name, stu.score[], stu.score[],stu.score[]);
- printf("\n");
- return ;
- }
- void change(struct student* p)
- {
- stru2 = *p;
- printf("add stru2 = %p\n", &stru2);
- printf("add (p) = %p\n",p);
- m_preferred_conn_params1 = *p->p_teacher;
- printf("*p.p_teacher = %p\n",*p.p_teacher); //编译错误
- printf("(*p)->p_teacher = %p\n",(*p)->p_teacher); //编译错误
- //m_preferred_conn_params1 = (*p).p_teacher; //error
- //m_preferred_conn_params1 = *p.p_teacher;//error
- printf("m_preferred_conn_params1.num = %d\n",m_preferred_conn_params1.num);
- printf("m_preferred_conn_params1.num2 = %d\n",m_preferred_conn_params1.num2);
- p->score[] = ;
- strcpy(p->name, "jerry");
- }
引言:
蓝牙协议栈中,有很多结构体方面的中高级应用,因此特意结合GDB调试来学习一下
详解:
change(&stu);把stu结构体的地址作为函数参数
- 运行效果:
- C:\Users\Administrator\Desktop # a.exe
- add stru2 =
- add (p) = 0028FEF8
- m_preferred_conn_params1.num =
- m_preferred_conn_params1.num2 =
- jerry
- 100.000000
- 89.000000
- 78.599998
- 添加gdb的选项-g
- C:\Users\Administrator\Desktop # gcc p_stuct.c -Wall -g
- Administrator@PC-20150323YSLL C:\Users\Administrator\Desktop # gdb a.exe
- GNU gdb (GDB) 7.5
- Copyright (C) Free Software Foundation, Inc.
- License GPLv3+: GNU GPL version or later <http://gnu.org/licenses/gpl.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law. Type "show copying"
- and "show warranty" for details.
- This GDB was configured as "i686-pc-mingw32".
- For bug reporting instructions, please see:
- <http://www.gnu.org/software/gdb/bugs/>.
- This binary was built by Equation Solution <http://www.Equation.com>...
- Reading symbols from C:\Users\Administrator\Desktop\a.exe...done.
- (gdb) l 相当于list
- struct student stru2;
- ble_gap_conn_params_t m_preferred_conn_params
- ={,};
- ble_gap_conn_params_t m_preferred_conn_params1;
- void change( struct student* stu );
- int main()
- {
- struct student stu;
- stu.num = ;
- (gdb) b 在程序28行添加断点,否则程序会直接运行下去,无法调试的。
- Breakpoint at 0x40135e: file p_stuct.c, line .
- (gdb) r 相当于run
- Starting program: C:\Users\Administrator\Desktop\a.exe
- [New Thread .0x1754]
- Breakpoint , main () at p_stuct.c:
- stu.num = ;
- (gdb) n 相当于next
- strcpy(stu.name, "Tom");
- (gdb) p stu 打印结构体的内容
- $ = {num = ,
- name = "b\021iu\304[nu\020\032@\000\224\377(\000n\032@",
- score = {5.88682122e-039, 6.45602865e-039,
- 5.32493416e-044}, p_teacher = 0x2}
- (gdb) n
- stu.score[] = 67.5;
- (gdb) n
- stu.score[] = ;
- (gdb) n
- stu.score[] = 78.6;
- (gdb) n
- stu.p_teacher = &m_preferred_conn_params;
- (gdb) n
- change(&stu);
- (gdb) p stu 赋值后,结构体的内容和程序中一样了。
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) bt 查看堆栈信息
- # main () at p_stuct.c:
- (gdb) p p
- No symbol "p" in current context.
- (gdb) r
- The program being debugged has been started already.
- Start it from the beginning? (y or n) y 因为没有进入子函数,所以直接运行后面的代码了。
- 重新启动调式代码
- Starting program: C:\Users\Administrator\Desktop\a.exe
- [New Thread .0x5c8]
- Breakpoint , main () at p_stuct.c:
- stu.num = ;
- (gdb) n
- strcpy(stu.name, "Tom");
- (gdb) n
- stu.score[] = 67.5;
- (gdb) n
- stu.score[] = ;
- (gdb) n
- stu.score[] = 78.6;
- (gdb) n
- stu.p_teacher = &m_preferred_conn_params;
- (gdb) p stu
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x2}
- (gdb) n
- change(&stu);
- (gdb) p stu
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) 直接回车重复上一个的命令
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) s 相当于step,会进入子函数
- change (p=0x28fef8) at p_stuct.c:
- stru2 = *p; 这个语句的意思是传递整个结构,在《c程序设计语言》第二版有写到。
- (gdb) l
- return ;
- }
- void change(struct student* p)
- {
- stru2 = *p;
- printf("add stru2 = %p\n", &stru2);
- printf("add (p) = %p\n",p);
- m_preferred_conn_params1 = *p->p_teacher;
- printf("m_preferred_conn_params1.num = %d\n",m_preferred_conn_params1.num);
- (gdb) bt
- # change (p=0x28fef8) at p_stuct.c:
- # 0x004013a5 in main () at p_stuct.c:
- (gdb) p p 结构体指针p的值,等于stu结构体的地址
- $ = (struct student *) 0x28fef8
- (gdb) n
- printf("add stru2 = %p\n", &stru2);
- (gdb) l
- }
- void change(struct student* p)
- {
- stru2 = *p;
- printf("add stru2 = %p\n", &stru2);
- printf("add (p) = %p\n",p);
- m_preferred_conn_params1 = *p->p_teacher;
- printf("m_preferred_conn_params1.num = %d\n",m_preferred_conn_params1.num);
- printf("m_preferred_conn_params1.num2 = %d\n",m_preferred_conn_params1.num2);
- (gdb) p stru2 因此stru2的内容和stu的内容是一样的。当然彼此内存地址是不一样的。
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) p *p====*p的内容和stu的内容是一样的。只是*pu是指针引用的方式来读取内容,
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) p *p.p_teacher
- $ = {num = , num2 = }
- 这个打印在gdb中是合法的,等价于*(p.p_teacher),()[] -> .四个优先级是最高的,其实语法书错的,编译后出错:
- C:\Users\Administrator\Desktop\p_stuct.c: In function 'change':
- C:\Users\Administrator\Desktop\p_stuct.c::: error: request for member 'p_tea
- cher' in something not a structure or union
- printf("*p.p_teacher = %p\n",*p.p_teacher);
- 因为p的指针,正确的用法是(*p).p_teacher
- (gdb) p *p-p 按tab键会有如下提示
- p printf_p_l
- p. printf_s
- p_teacher printf_s_l
- pclose purecall
- pctype putc
- perror putch
- pfnFreeRoutines putchar
- pfnMarshallRoutines putenv
- pfnSizeRoutines putenv_s
- pfnUnmarshallRoutines puts
- pgmptr putw
- pipe putwc
- popen putwch
- pow putwchar
- printf putws
- printf_l pwctype
- printf_p
- (gdb) p *p->p_teacher 这个打印在gdb,gcc中都是合法的,等价于*(p->p_teacher),()[] -> . 四个优先级是最高的.
- $ = {num = , num2 = }
- (gdb) l
- p->score[] = ;
- strcpy(p->name, "jerry");
- }
- (gdb) n
- add stru2 =
- printf("add (p) = %p\n",p);
- (gdb) p p->p_teacher 打印结构体的成员,是一个指向另一结构体的指针
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p *(p->p_teacher)
- $ = {num = , num2 = }
- (gdb) p *(p)->p_teacher 这个打印在gdb中也是合法的,多了()效果等于没有加
- $ = {num = , num2 = }
- (gdb) p (*p)->p_teacher
- $ = (ble_gap_conn_params_t *) 0x402000
- 这个打印在gdb中也是合法的,但gcc编译时错误的,因为语法错误,在dennis经典教材中,没有这样的语法。
- C:\Users\Administrator\Desktop\p_stuct.c: In function 'change':
- C:\Users\Administrator\Desktop\p_stuct.c::: error: invalid type argument of
- '->' (have 'struct student')
- printf("(*p)->p_teacher = %p\n",(*p)->p_teacher);
- (gdb) p m_preferred_conn_params
- $ = {num = , num2 = }
- (gdb) p &m_preferred_conn_params
- $ = (ble_gap_conn_params_t *) 0x402000 p_teacher的值就是0x402000,说明p_teacher指向这个结构体
- 通过m_preferred_conn_params1 = *p->p_teacher;结构体m_preferred_conn_params1的内容如下:
- (gdb) p &m_preferred_conn_params1
- $ = (ble_gap_conn_params_t *) 0x405060
- (gdb) p m_preferred_conn_params1
- $ = {num = , num2 = }
- 等价于内存0x402000的内容拷贝到0x405060中。
- (gdb) p p->name
- $ = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@"
- (gdb) p p->p_teacher
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p *(p->p_teacher)
- $ = {num = , num2 = }
- (gdb) p *p->p_teacher
- $ = {num = , num2 = }
- 上面两个是等价的
- (gdb) p (*p)->p_teacher 语法其实是错误的
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p (*p).p_teacher 语法其实是错误的
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p *p.p_teacher 语法其实是错误的
- $ = {num = , num2 = }
- (gdb) p p.p_teacher 语法其实是错误的
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p p->p_teacher
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p &m_preferred_conn_params1
- $ = (ble_gap_conn_params_t *) 0x405060
- (gdb) p &m_preferred_conn_params
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p p
- $ = (struct student *) 0x28fef8
- (gdb) p *p
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) p &(p->p_teacher )
- $ = (ble_gap_conn_params_t **) 0x28ff1c
- (gdb) p p
- $ = (struct student *) 0x28fef8
- (gdb) x 0x28fef8
- 0x28fef8: 0x00003039
- (gdb) p stu 在子函数是打印main函数中的变量是无效的
- No symbol "stu" in current context.
- (gdb) display p 另一种打印的方式,可以累加
- : p = (struct student *) 0x28fef8
- (gdb) display *p
- : *p = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) display 累加之前的打印信息。全都打印出来。可以用undisplay取消打印,Delete all auto-display expressions? (y or n) y
- : *p = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- : p = (struct student *) 0x28fef8
- (gdb) p &p 结构体指针p的地址,其实也就是结构体stu的地址,但两者含义有所不同,一个是真实的结构体,一个是指向结构体的指针
- $ = (struct student **) 0x28fec0
- 打印每个成员的地址
- (gdb) p &(p->num )
- $ = (int *) 0x28fef8
- (gdb) p &(p->name )
- $ = (char (*)[]) 0x28fefc
- (gdb) p &(p->score )
- $ = (float (*)[]) 0x28ff10 0x28ff10-0x28fefc=0x14 = 20个字节,刚好等于char name[];的大小
- (gdb) p &(p->p_teacher)
- $ = (ble_gap_conn_params_t **) 0x28ff1c 0x28ff1c-0x28ff10=0xc,等于12个字节,说明float变量在本系统中是占用4个字节大小。
- (gdb) p p
- $ = (struct student *) 0x28fef8
- (gdb) p *p
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
- (gdb) p (p->p_teacher)
- $ = (ble_gap_conn_params_t *) 0x402000
- (gdb) p stru2
- $ = {num = ,
- name = "Tom\000\304[nu\020\032@\000\224\377(\000n\032@",
- score = {67.5, , 78.5999985}, p_teacher = 0x402000}
学习中,参考了gdb的教程:
https://www.cnblogs.com/klcf0220/p/5627125.html
https://blog.csdn.net/haoel/article/details/2879
以及c语句的经典教材《C程序设计语言》第二版
结构体指针:http://www.cnblogs.com/cmyg/p/6910860.html
GDB在学习C语言中很有用,但是要和真正的C语言语法相结合,同时要学会画“内存图”,这样才能理解深入。
学习蓝牙协议栈,发现自己C语言还是需要经常学习的。有很多高级的用法。好的教材要多多看几遍。
C语言结构体的学习,以及gdb的调式的更多相关文章
- 漫谈C语言结构体
相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...
- 漫谈C语言结构体【转】
相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...
- Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- C语言 结构体学习
结构体的学习 struct 结构是由基本数据类型构成的.并用一个标识符来命名的各种变量的组合. 结构中可以使用不同的数据类型. 结构说明和结构变量定义 在Turbo C中, 结构也是一种数据类型,可以 ...
- GO语言学习(十六)Go 语言结构体
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...
- 对嵌入式开发C语言结构体的一点总结
今天冬至居然不上班,公司的良心啊!这回有心情写博客和日志了,好了,废话不多说.直接看下文: 鉴于嵌入式开发过程中,C语言结构体的使用当然是必不可少.话说,基础什么的比你会更牛逼的算法更重要,基础不牢, ...
- 读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组
原文链接:C语言结构体里的成员数组和指针 复制例如以下: 单看这文章的标题,你可能会认为好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Lar ...
- C/C++语言结构体指针的使用
C/C++语言结构体指针的使用 主要内容 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使用 指针的使用 代码内容重点 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使 ...
- 漫谈C语言结构体struct、公用体union空间占用
先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; u ...
随机推荐
- (六)svn 服务器端使用之权限管理
权限管理(了解) 认证授权机制 在企业开发中会为每位程序员.测试人员等相关人员分配一个账号,用户通过使用svn客户端连接svn服务时需要输入账号和密码,svn服务对账号和密码进行校验,输入正确可以继续 ...
- Linux添加alias简化命令
一.简介 linux alias 是命令的一种别称,输入 alias 可以看到像下面这样的结果: alias vi="vim" 也即,输入vi后,被自动定向到vim这个命令了.al ...
- Linux --Mysql数据库搭建
Mysql数据库 安装 准备: [root@localhost /]# rpm -e mysql --nodeps 将rpm方式安装的mysql卸载 [root@localhost /]# gro ...
- *92. Reverse Linked List II (follow up questions)
Reverse a linked list from position m to n. Do it in one-pass and in-place Note: 1 ≤ m ≤ n ≤ length ...
- GPU使用
GPU .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1p ...
- maven项目发布到Tomcat丢失jar包
昨天看了一篇tomcat设置的文章,说要把第一个勾上,这样不需要更新到tomcat. 一启动tomcat就发现丢包.后来在网上看了许多文章,说要update maeven项目,然后你就会发现启动过程 ...
- P3909 异或之积
P3909 异或之积 为什么叫做异或之积? 答曰:只要不关乎Alice和Bob就行 做完这道水题,感觉自己弱爆了. 一开始就要考虑暴力\(O(n^3)\)的优化. 然后就注意到了题目中的\(6\)为什 ...
- ADO.NET 之 Entity Framework 基础
Entity Framework(EF)是使用直接映射到应用程序中业务对象的对象模型于关系数据库进行交互.它没有将数据视为行和列的集合,而是将其视为强类型对象(成为实体)的集合. 术语:LinQ to ...
- <body> 中的 JavaScript 函数
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- 22.访问jar包下资源路径里的文件
访问jar包下资源路径里的文件 因为打包路径和你构建的代码路径是有差异的,想要查看真实的路径情况,可以查看编译后的classes目录下的文件结构. 想要获取资源文件流: private InputSt ...