#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的调式的更多相关文章

  1. 漫谈C语言结构体

    相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...

  2. 漫谈C语言结构体【转】

    相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...

  3. Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  4. C语言 结构体学习

    结构体的学习 struct 结构是由基本数据类型构成的.并用一个标识符来命名的各种变量的组合. 结构中可以使用不同的数据类型. 结构说明和结构变量定义 在Turbo C中, 结构也是一种数据类型,可以 ...

  5. GO语言学习(十六)Go 语言结构体

    Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...

  6. 对嵌入式开发C语言结构体的一点总结

    今天冬至居然不上班,公司的良心啊!这回有心情写博客和日志了,好了,废话不多说.直接看下文: 鉴于嵌入式开发过程中,C语言结构体的使用当然是必不可少.话说,基础什么的比你会更牛逼的算法更重要,基础不牢, ...

  7. 读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组

    原文链接:C语言结构体里的成员数组和指针 复制例如以下: 单看这文章的标题,你可能会认为好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Lar ...

  8. C/C++语言结构体指针的使用

    C/C++语言结构体指针的使用 主要内容 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使用 指针的使用 代码内容重点 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使 ...

  9. 漫谈C语言结构体struct、公用体union空间占用

    先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; u ...

随机推荐

  1. percona mysql 5.7再centerOS 7上的安装

    第一次测试装的,还不是很熟练.很多东西不太对,以后还回改进 一.卸载包检查是否安装有MySQL Server: rpm -qa | grep mysql rpm -qa | grep mariadb ...

  2. Git/Github Learning

    通过网上查找资料,我了解到Git/Github是一款免费.开源的分布式版本控制系统,它可以敏捷高效地处理任何或小或大的项目.同时,它是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的 ...

  3. IOS6 的特性 及 autoalyout的作用

    1.如果控件有默认的内容(宽高), 我们只需设置autoalyout的X/Y, autolayout会自动计算出宽高 2.Xcode6将Storyboard变成豆腐干的目的:在Xcode6之前, 如果 ...

  4. C++11之 Move semantics(移动语义)(转)

    转https://blog.csdn.net/wangshubo1989/article/details/49748703 按值传递的意义是什么? 当一个函数的参数按值传递时,这就会进行拷贝.当然,编 ...

  5. 十天精通CSS3

    课程地址:http://www.imooc.com/learn/33 第1章 初识CSS3 CSS3课程列出第一站,先带领大家进入CSS3的世界,探索CSS3的魅力! 你做好准备了吗? 第2章 边框 ...

  6. [JSOI2010]部落划分

    嘟嘟嘟 一道不错的题,解法不少. 最易于理解的是最小生成树的做法: 首先每两个点之间都连一条长度为这两个点的距离的边,形成完全图. 然后跑最小生成树,直到剩k个联通块,这时候合并成k - 1个联通块的 ...

  7. Visual Studio C++ Win32控制台应用程序,Win32项目,MFC的区别

    背景 Visual Studio C++ 创建新项目蹦出来如下选项: Win32控制台应用程序,Win32项目,MFC有什么区别? 正文: Win32控制台,没有界面,命令行执行生成的文件则直接在后台 ...

  8. nginx 图片,js,css等文件允许跨域

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ { #允许跨域请求 add_header Access-Control-Allow-Ori ...

  9. 封装方法到对象(javascript)

    /*! * artDialog 5 * Date: 2012-03-21 * http://code.google.com/p/artdialog/ * (c) 2009-2012 TangBin, ...

  10. sudo cd的错误

    问题说明 今天用MySQL建了库,想看看. 当到了这步,心里的第一个感觉就是电脑坏了.后来查了查才知道了原因. 原因 cd不是一个应用程序而是Linux内建的命令,而sudo仅仅只对应用程序起作用. ...