zoukankan      html  css  js  c++  java
  • C语言结构体的学习,以及gdb的调式

     1 #include <stdio.h>
     2 #include <string.h>
     3 #define format "%d
    %s
    %f
    %f
    %f
    "
     4 
     5 
     6 typedef struct
     7 {
     8     int num;
     9     int num2;      
    10 } ble_gap_conn_params_t;
    11 
    12 struct student
    13 {
    14     int num;
    15     char name[20];
    16     float score[3];
    17     ble_gap_conn_params_t * p_teacher;
    18 };
    19 
    20 
    21 struct student stru2;
    22 ble_gap_conn_params_t m_preferred_conn_params
    23 ={0,2};
    24 ble_gap_conn_params_t m_preferred_conn_params1;
    25 void change( struct student* stu );
    26 int main()
    27 {
    28     struct student stu, p_stu;
    29     stu.num = 12345;
    30     strcpy(stu.name, "Tom");
    31     stu.score[0] = 67.5;
    32     stu.score[1] = 89;
    33     stu.score[2] = 78.6;
    34     stu.p_teacher = &m_preferred_conn_params;
    35     p_stu = stu;
    36     printf("p_stu.num = %d
    ",p_stu.num);
    37     change(&stu);
    38     printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]);
    39     printf("
    ");
    40     return 0;
    41 }
    42  
    43 void change(struct student* p)
    44 {
    45     stru2 = *p;
    46     printf("add stru2 = %p
    ", &stru2);
    47     printf("add (p) = %p
    ",p);
    48     m_preferred_conn_params1 = *p->p_teacher;
    49     printf("*p.p_teacher = %p
    ",*p.p_teacher);  //编译错误
    50     printf("(*p)->p_teacher = %p
    ",(*p)->p_teacher);  //编译错误
    51     //m_preferred_conn_params1 = (*p).p_teacher;    //error
    52     //m_preferred_conn_params1 = *p.p_teacher;//error
    53     printf("m_preferred_conn_params1.num = %d
    ",m_preferred_conn_params1.num);
    54     printf("m_preferred_conn_params1.num2 = %d
    ",m_preferred_conn_params1.num2);
    55     p->score[0] = 100;
    56     strcpy(p->name, "jerry");
    57 }

    引言:
    蓝牙协议栈中,有很多结构体方面的中高级应用,因此特意结合GDB调试来学习一下
    详解:
    change(&stu);把stu结构体的地址作为函数参数

      1 运行效果:
      2 C:UsersAdministratorDesktop # a.exe
      3 add stru2 = 00405080
      4 add (p) = 0028FEF8
      5 m_preferred_conn_params1.num = 0
      6 m_preferred_conn_params1.num2 = 2
      7 12345
      8 jerry
      9 100.000000
     10 89.000000
     11 78.599998
     12 添加gdb的选项-g
     13 
     14 C:UsersAdministratorDesktop # gcc p_stuct.c -Wall -g
     15 
     16 Administrator@PC-20150323YSLL C:UsersAdministratorDesktop # gdb a.exe
     17 GNU gdb (GDB) 7.5
     18 Copyright (C) 2012 Free Software Foundation, Inc.
     19 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
     20 This is free software: you are free to change and redistribute it.
     21 There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
     22 and "show warranty" for details.
     23 This GDB was configured as "i686-pc-mingw32".
     24 For bug reporting instructions, please see:
     25 <http://www.gnu.org/software/gdb/bugs/>.
     26 This binary was built by Equation Solution <http://www.Equation.com>...
     27 Reading symbols from C:UsersAdministratorDesktopa.exe...done.
     28 (gdb) l                相当于list
     29 20
     30 21      struct student stru2;
     31 22      ble_gap_conn_params_t m_preferred_conn_params
     32 23      ={0,2};
     33 24      ble_gap_conn_params_t m_preferred_conn_params1;
     34 25      void change( struct student* stu );
     35 26      int main()
     36 27      {
     37 28              struct student stu;
     38 29              stu.num = 12345;
     39 (gdb) b 28                    在程序28行添加断点,否则程序会直接运行下去,无法调试的。
     40 Breakpoint 1 at 0x40135e: file p_stuct.c, line 28.
     41 (gdb) r                    相当于run
     42 Starting program: C:UsersAdministratorDesktopa.exe
     43 [New Thread 976.0x1754]
     44 
     45 Breakpoint 1, main () at p_stuct.c:29
     46 29              stu.num = 12345;
     47 (gdb) n            相当于next
     48 30              strcpy(stu.name, "Tom");
     49 (gdb) p stu        打印结构体的内容
     50 $1 = {num = 12345,
     51   name = "b21iu304[nu2032@00224377(00n32@",
     52   score = {5.88682122e-039, 6.45602865e-039,
     53     5.32493416e-044}, p_teacher = 0x2}
     54 (gdb) n
     55 31              stu.score[0] = 67.5;
     56 (gdb) n
     57 32              stu.score[1] = 89;
     58 (gdb) n
     59 33              stu.score[2] = 78.6;
     60 (gdb) n
     61 34              stu.p_teacher = &m_preferred_conn_params;
     62 (gdb) n
     63 35              change(&stu);
     64 (gdb) p stu            赋值后,结构体的内容和程序中一样了。
     65 $2 = {num = 12345,
     66   name = "Tom00304[nu2032@00224377(00n32@",
     67   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
     68 
     69 40
     70 (gdb) bt        查看堆栈信息
     71 #0  main () at p_stuct.c:36
     72 (gdb) p p
     73 No symbol "p" in current context.
     74 (gdb) r
     75 The program being debugged has been started already.
     76 Start it from the beginning? (y or n) y        因为没有进入子函数,所以直接运行后面的代码了。
     77 重新启动调式代码
     78 Starting program: C:UsersAdministratorDesktopa.exe
     79 [New Thread 5260.0x5c8]
     80 
     81 Breakpoint 1, main () at p_stuct.c:29
     82 29              stu.num = 12345;
     83 (gdb) n
     84 30              strcpy(stu.name, "Tom");
     85 (gdb) n
     86 31              stu.score[0] = 67.5;
     87 (gdb) n
     88 32              stu.score[1] = 89;
     89 (gdb) n
     90 33              stu.score[2] = 78.6;
     91 (gdb) n
     92 34              stu.p_teacher = &m_preferred_conn_params;
     93 (gdb) p stu
     94 $3 = {num = 12345,
     95   name = "Tom00304[nu2032@00224377(00n32@",
     96   score = {67.5, 89, 78.5999985}, p_teacher = 0x2}
     97 (gdb) n
     98 35              change(&stu);
     99 (gdb) p stu
    100 $4 = {num = 12345,
    101   name = "Tom00304[nu2032@00224377(00n32@",
    102   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    103 (gdb)        直接回车重复上一个的命令
    104 $5 = {num = 12345,
    105   name = "Tom00304[nu2032@00224377(00n32@",
    106   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    107 (gdb) s            相当于step,会进入子函数
    108 change (p=0x28fef8) at p_stuct.c:43
    109 43              stru2 = *p;    这个语句的意思是传递整个结构,在《c程序设计语言》第二版有写到。
    110 (gdb) l
    111 38              return 0;
    112 39      }
    113 40
    114 41      void change(struct student* p)
    115 42      {
    116 43              stru2 = *p;
    117 44              printf("add stru2 = %p
    ", &stru2);
    118 45              printf("add (p) = %p
    ",p);
    119 46              m_preferred_conn_params1 = *p->p_teacher;
    120 47              printf("m_preferred_conn_params1.num = %d
    ",m_preferred_conn_params1.num);
    121 (gdb) bt
    122 #0  change (p=0x28fef8) at p_stuct.c:43
    123 #1  0x004013a5 in main () at p_stuct.c:35
    124 (gdb) p p        结构体指针p的值,等于stu结构体的地址
    125 $6 = (struct student *) 0x28fef8
    126 (gdb) n
    127 44              printf("add stru2 = %p
    ", &stru2);
    128 (gdb) l
    129 39      }
    130 40
    131 41      void change(struct student* p)
    132 42      {
    133 43              stru2 = *p;
    134 44              printf("add stru2 = %p
    ", &stru2);
    135 45              printf("add (p) = %p
    ",p);
    136 46              m_preferred_conn_params1 = *p->p_teacher;
    137 47              printf("m_preferred_conn_params1.num = %d
    ",m_preferred_conn_params1.num);
    138 48              printf("m_preferred_conn_params1.num2 = %d
    ",m_preferred_conn_params1.num2);
    139 (gdb) p stru2        因此stru2的内容和stu的内容是一样的。当然彼此内存地址是不一样的。
    140 $7 = {num = 12345,
    141   name = "Tom00304[nu2032@00224377(00n32@",
    142   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    143 (gdb) p *p====*p的内容和stu的内容是一样的。只是*pu是指针引用的方式来读取内容,
    144 $8 = {num = 12345,
    145   name = "Tom00304[nu2032@00224377(00n32@",
    146   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    147 (gdb) p *p.p_teacher
    148 $10 = {num = 0, num2 = 2}
    149     这个打印在gdb中是合法的,等价于*(p.p_teacher),()[] -> .四个优先级是最高的,其实语法书错的,编译后出错:
    150 C:UsersAdministratorDesktopp_stuct.c: In function 'change':
    151 C:UsersAdministratorDesktopp_stuct.c:49:35: error: request for member 'p_tea
    152 cher' in something not a structure or union
    153   printf("*p.p_teacher = %p
    ",*p.p_teacher);
    154 因为p的指针,正确的用法是(*p).p_teacher
    155 (gdb) p *p-p        按tab键会有如下提示
    156 p                      printf_p_l
    157 p.1761                 printf_s
    158 p_teacher              printf_s_l
    159 pclose                 purecall
    160 pctype                 putc
    161 perror                 putch
    162 pfnFreeRoutines        putchar
    163 pfnMarshallRoutines    putenv
    164 pfnSizeRoutines        putenv_s
    165 pfnUnmarshallRoutines  puts
    166 pgmptr                 putw
    167 pipe                   putwc
    168 popen                  putwch
    169 pow                    putwchar
    170 printf                 putws
    171 printf_l               pwctype
    172 printf_p
    173 (gdb) p *p->p_teacher    这个打印在gdb,gcc中都是合法的,等价于*(p->p_teacher),()[] -> . 四个优先级是最高的.
    174 $11 = {num = 0, num2 = 2}
    175 (gdb) l
    176 49              p->score[0] = 100;
    177 50              strcpy(p->name, "jerry");
    178 51      }
    179 (gdb) n
    180 add stru2 = 00405080
    181 45              printf("add (p) = %p
    ",p);
    182 (gdb) p p->p_teacher    打印结构体的成员,是一个指向另一结构体的指针
    183 $12 = (ble_gap_conn_params_t *) 0x402000
    184 (gdb) p *(p->p_teacher)
    185 $13 = {num = 0, num2 = 2}
    186 (gdb) p *(p)->p_teacher        这个打印在gdb中也是合法的,多了()效果等于没有加
    187 $14 = {num = 0, num2 = 2}
    188 (gdb) p (*p)->p_teacher
    189 $15 = (ble_gap_conn_params_t *) 0x402000
    190 这个打印在gdb中也是合法的,但gcc编译时错误的,因为语法错误,在dennis经典教材中,没有这样的语法。
    191 C:UsersAdministratorDesktopp_stuct.c: In function 'change':
    192 C:UsersAdministratorDesktopp_stuct.c:50:38: error: invalid type argument of
    193 '->' (have 'struct student')
    194   printf("(*p)->p_teacher = %p
    ",(*p)->p_teacher);
    195 
    196 (gdb) p m_preferred_conn_params
    197 $17 = {num = 0, num2 = 2}
    198 (gdb) p &m_preferred_conn_params
    199 $18 = (ble_gap_conn_params_t *) 0x402000        p_teacher的值就是0x402000,说明p_teacher指向这个结构体
    200 通过m_preferred_conn_params1 = *p->p_teacher;结构体m_preferred_conn_params1的内容如下:
    201 (gdb) p &m_preferred_conn_params1
    202 $20 = (ble_gap_conn_params_t *) 0x405060
    203 (gdb) p m_preferred_conn_params1
    204 $21 = {num = 0, num2 = 2}
    205 等价于内存0x402000的内容拷贝到0x405060中。
    206 (gdb) p p->name
    207 $23 = "Tom00304[nu2032@00224377(00n32@"
    208 (gdb) p p->p_teacher
    209 $24 = (ble_gap_conn_params_t *) 0x402000
    210 (gdb) p *(p->p_teacher)
    211 $25 = {num = 0, num2 = 2}
    212 (gdb) p *p->p_teacher
    213 $26 = {num = 0, num2 = 2}
    214 上面两个是等价的
    215 (gdb) p (*p)->p_teacher    语法其实是错误的
    216 $27 = (ble_gap_conn_params_t *) 0x402000
    217 (gdb) p (*p).p_teacher    语法其实是错误的
    218 $29 = (ble_gap_conn_params_t *) 0x402000
    219 (gdb) p *p.p_teacher    语法其实是错误的
    220 $30 = {num = 0, num2 = 2}
    221 (gdb) p p.p_teacher        语法其实是错误的
    222 $31 = (ble_gap_conn_params_t *) 0x402000
    223 (gdb) p p->p_teacher
    224 $32 = (ble_gap_conn_params_t *) 0x402000
    225 
    226 (gdb) p &m_preferred_conn_params1
    227 $35 = (ble_gap_conn_params_t *) 0x405060
    228 (gdb) p &m_preferred_conn_params
    229 $36 = (ble_gap_conn_params_t *) 0x402000
    230 (gdb) p p
    231 $37 = (struct student *) 0x28fef8
    232 (gdb) p *p
    233 $38 = {num = 12345,
    234   name = "Tom00304[nu2032@00224377(00n32@",
    235   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    236 
    237 (gdb) p &(p->p_teacher )
    238 $39 = (ble_gap_conn_params_t **) 0x28ff1c
    239 (gdb) p p
    240 $40 = (struct student *) 0x28fef8
    241 (gdb) x 0x28fef8
    242 0x28fef8:       0x00003039
    243 (gdb) p stu        在子函数是打印main函数中的变量是无效的
    244 No symbol "stu" in current context.
    245 (gdb) display p        另一种打印的方式,可以累加
    246 1: p = (struct student *) 0x28fef8
    247 (gdb) display *p
    248 2: *p = {num = 12345,
    249   name = "Tom00304[nu2032@00224377(00n32@",
    250   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    251 (gdb) display        累加之前的打印信息。全都打印出来。可以用undisplay取消打印,Delete all auto-display expressions? (y or n) y
    252 2: *p = {num = 12345,
    253   name = "Tom00304[nu2032@00224377(00n32@",
    254   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    255 1: p = (struct student *) 0x28fef8
    256 (gdb) p &p        结构体指针p的地址,其实也就是结构体stu的地址,但两者含义有所不同,一个是真实的结构体,一个是指向结构体的指针
    257 $41 = (struct student **) 0x28fec0
    258 打印每个成员的地址
    259 (gdb) p &(p->num )
    260 $44 = (int *) 0x28fef8
    261 (gdb) p &(p->name )
    262 $45 = (char (*)[20]) 0x28fefc
    263 (gdb) p &(p->score )
    264 $46 = (float (*)[3]) 0x28ff10        0x28ff10-0x28fefc=0x14 = 20个字节,刚好等于char name[20];的大小
    265 (gdb) p &(p->p_teacher)
    266 $47 = (ble_gap_conn_params_t **) 0x28ff1c    0x28ff1c-0x28ff10=0xc,等于12个字节,说明float变量在本系统中是占用4个字节大小。
    267 (gdb) p p
    268 $48 = (struct student *) 0x28fef8
    269 (gdb) p *p
    270 $49 = {num = 12345,
    271   name = "Tom00304[nu2032@00224377(00n32@",
    272   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    273 (gdb) p (p->p_teacher)
    274 $50 = (ble_gap_conn_params_t *) 0x402000
    275 (gdb) p stru2
    276 $51 = {num = 12345,
    277   name = "Tom00304[nu2032@00224377(00n32@",
    278   score = {67.5, 89, 78.5999985}, p_teacher = 0x402000}
    279 
    280     

    学习中,参考了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语言还是需要经常学习的。有很多高级的用法。好的教材要多多看几遍。

  • 相关阅读:
    python面向对象中的一些特殊__方法__
    mysql数据库的优化和查询效率的优化
    详解python的垃圾回收机制
    基于django的自定义简单session功能
    使用python制作验证码
    Netty 系列之 Netty 高性能之道
    Java提高篇(二七)-----TreeMap
    Oracle、MySql、SQLServer 数据分页查询
    深入理解数据库原理系列(1)---日志系统原理
    34个数据库常见面试题讲解
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/10726697.html
Copyright © 2011-2022 走看看