C指针原理(20)-C指针基础
2018-12-28 12:59:57
結構與malloc
結構是C語言中重要的一環(huán),malloc是一個重要的函數(shù),它完成了動態(tài)內存分配,用malloc分配的內存塊要通過free釋放。通過結構可以將不同類型的數(shù)據(jù)組合成一個整體,關于結構指針,LINUX下編程經(jīng)常會運用一個技巧,這個技巧用在申請緩沖區(qū)上,可以申請不同大小的緩沖區(qū)。
首先,來看一個概念消息隊列 ,一個或多個進程可向消息隊列寫入消息,而一個或多個進程可從消息隊列中讀取消息,Linux中的消息被描述成在內核地址空間的一個內部鏈表,每一個消息隊列由一個IPC的標識號唯一的標識,Linux 為系統(tǒng)中所有的消息隊列維護一個 msgque 鏈表,每個消息隊列都在系統(tǒng)范圍內對應唯一的鍵值,要獲得一個消息隊列的描述字,只需提供該消息隊列的鍵值即可。
傳遞給隊列的消息的數(shù)據(jù)類型是一個如下形式的結構,在Linux 的系統(tǒng)庫linux/msg.h 中,它是這樣定義的:
/ message buffer for msgsnd and msgrcv calls /
struct msgbuf {
long mtype; / type of message /
char mtext[1]; / message text /
};
其中,mtype成員代表消息類型,從消息隊列中讀取消息的一個重要依據(jù)就是消息的類型;mtext是消息內容。這個結構的精妙之處在于,mtext雖然在結構中被聲明為大小為1的字符,但實際消息內容的長度可以由程序員任意定制,定制的關鍵在malloc函數(shù)。下面是部分代碼段:
msg=(struct msgbuf*)malloc(sizeof(struct msgbuf)+100);//100為消息的長度,msgbuf結構只有2個成員一個成員是mytpe,另一個成員是一個字節(jié)的mtext,在結構后分配更多的空間以存放消息字符串
完整代碼(演示了公共消息隊列的使用)為:
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#define QUE_ID 2
//使用公共消息隊列,讀寫進程可以不同時運行。
int main(void){
int queue_id;
struct msgbuf *msg;
int rc;
}
以上是發(fā)送消息,以下是接收消息
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#define QUE_ID 2
//使用公共消息隊列,讀寫進程可以不同時運行。
int main(void){
int queue_id;
struct msgbuf *msg;
int rc;
}
效果
deepfuture@deepfuture-laptop:~/private/mytest$ ./testmessnd
message 0 queue created!
message send…
message sended!
deepfuture@deepfuture-laptop:~/private/mytest$ ./testmesrecv
message recv…
recv:deepfuture.iteye.com
deepfuture@deepfuture-laptop:~/private/mytest$
7、字符串常量
#include <stdio.h>
int main(int argc,int **argv){
printf ("%s","abcdefgh"+2);}
dp@dp:~/test1 % cc test3.c -o mytest
dp@dp:~/test1 % ./mytest
cdefgh
8、函數(shù)指針
通過如下格式來聲明函數(shù)指針:
返回類型 (*函數(shù)指針變量名)(參數(shù)列表)
int add(int a,int b);
int main(void){
int (*myfunc)(int a,int b);myfunc=add;int x=myfunc(12,36);printf("%d",x);return 1;}
int add(int a,int b){
return a+b;}
~
dp@dp:~/test1 % cc test1.c -o mytest
dp@dp:~/test1 % ./mytest
48
8、命令行參數(shù)
打印參數(shù)個數(shù),注意,命令本身也是一個參數(shù),所以argc至少為1。
#include <stdio.h>
int main(int argc,char **argv){
printf("%d\n",argc);return 1;}
~
dp@dp:~/test1 % cc test2.c -o mytest
dp@dp:~/test1 % ./mytest 12
下面沒有使用argc參數(shù),直接使用了argv參數(shù),通過判斷是否null,來決定參數(shù)列表是否結束
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char **argv){
while (*++argv!=NULL)printf("%d\n",argv);return 1;}
~
dp@dp:~/test1 % cc test2.c -o mytest
dp@dp:~/test1 % ./mytest -a
-a
dp@dp:~/test1 % ./mytest -a 12 24
-a
12
24
通過如下格式來聲明函數(shù)指針數(shù)組:
返回類型 (*函數(shù)指針變量名[])(參數(shù)列表)
下面結合函數(shù)指針數(shù)組與命令行完成一些簡單的運算,通過命令行傳送運算符與數(shù)字。
#include <stdio.h>#include <stdlib.h>int add(int a,int b){return a+b;}int sub(int a,int b){return a-b;}int main(int argc,char **argv){int (*operate_func[])(int,int)={add,sub};int myresult=0;int oper=atoi(*++argv);printf ("%d\n",oper);int mynum;while (*++argv!=NULL){mynum=atoi(*argv);printf ("%d ",mynum);myresult=operate_func[oper](myresult,mynum);}printf ("\n%d\n",myresult);return 1;}dp@dp:~/test1 % cc test2.c -o mytest
dp@dp:~/test1 % ./mytest 0 1 13 52
0
1 13 52
66
dp@dp:~/test1 % ./mytest 1 1 13 52
1
1 13 52
-66
dp@dp:~/test1 %
1、將C文件生成中間匯編
$ gcc -S hello.c
.file "hello.c".section .rodata.LC0:.string "hello,world".text.globl main.type main, @functionmain:pushl %ebpmovl %esp, %ebpandl $-16, %espsubl $16, %espmovl $.LC0, (%esp)call putsmovl $0, (%esp)call exit.size main, .-main.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3".section .note.GNU-stack,"",@progbits2、gdb調試
deepfuture@deepfuture-laptop:~/private/mytest$ gcc -gstabs -o hello hello.c
hello.c: In function ‘main’:
hello.c:4: warning: incompatible implicit declaration of built-in function ‘exit’
deepfuture@deepfuture-laptop:~/private/mytest$ gdb
GNU gdb (GDB) 7.1-ubuntu
Copyright ? 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 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 “i486-linux-gnu”.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/;.
(gdb) file hello
Reading symbols from /home/deepfuture/private/mytest/hello…done.
(gdb) list
1 #include <stdio.h>
2 int main(){
3 printf(“hello,world\n”);
4 exit(0);
5 }
(gdb) break 3
Breakpoint 1 at 0x804841d: file hello.c, line 3.
(gdb) run
Starting program: /home/deepfuture/private/mytest/hello
Breakpoint 1, main () at hello.c:3
3 printf(“hello,world\n”);
(gdb) c
Continuing.
hello,world
Program exited normally.
(gdb) quit
3、gprof圖表簡檔,可進行程序相關性能統(tǒng)計,可統(tǒng)計出每個函數(shù)的調用時間 和處理器時間
deepfuture@deepfuture-laptop:~/private/mytest$ gcc -pg -o hello hello.c
hello.c: In function ‘main’:
hello.c:4: warning: incompatible implicit declaration of built-in function ‘exit’
deepfuture@deepfuture-laptop:~/private/mytest$ ./hello
hello,world
deepfuture@deepfuture-laptop:~/private/mytest$ gprof hello>myhello.txt
deepfuture@deepfuture-laptop:~/private/mytest$ cat myhello.txt
Flat profile:
Each sample counts as 0.01 seconds.
no time accumulated
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
% the percentage of the total running time of the
time program used by this function.
cumulative a running sum of the number of seconds accounted
seconds for by this function and those listed above it.
self the number of seconds accounted for by this
seconds function alone. This is the major sort for this
listing.calls the number of times this function was invoked, if
this function is profiled, else blank.self the average number of milliseconds spent in this
ms/call function per call, if this function is profiled,
else blank.
total the average number of milliseconds spent in this
ms/call function and its descendents per call, if this
function is profiled, else blank.
name the name of the function. This is the minor sort
for this listing. The index shows the location ofthe function in the gprof listing. If the index is
in parenthesis it shows where it would appear in
the gprof listing if it were to be printed.
4、反匯編objdump
deepfuture@deepfuture-laptop:~/private/mytest$ objdump -d hello
hello: file format elf32-i386Disassembly of section .init:080482dc <_init>:80482dc: 55 push %ebp80482dd: 89 e5 mov %esp,%ebp80482df: 53 push %ebx80482e0: 83 ec 04 sub $0x4,%esp80482e3: e8 00 00 00 00 call 80482e8 <_init+0xc>80482e8: 5b pop %ebx80482e9: 81 c3 0c 1d 00 00 add $0x1d0c,%ebx80482ef: 8b 93 fc ff ff ff mov -0x4(%ebx),%edx80482f5: 85 d2 test %edx,%edx80482f7: 74 05 je 80482fe <_init+0x22>80482f9: e8 1e 00 00 00 call 804831c <__gmon_start__@plt>80482fe: e8 ed 00 00 00 call 80483f0 <frame_dummy>8048303: e8 a8 01 00 00 call 80484b0 <__do_global_ctors_aux>8048308: 58 pop %eax8048309: 5b pop %ebx804830a: c9 leave 804830b: c3 ret Disassembly of section .plt:0804830c <__gmon_start__@plt-0x10>:804830c: ff 35 f8 9f 04 08 pushl 0x8049ff88048312: ff 25 fc 9f 04 08 jmp *0x8049ffc8048318: 00 00 add %al,(%eax)...0804831c <__gmon_start__@plt>:804831c: ff 25 00 a0 04 08 jmp *0x804a0008048322: 68 00 00 00 00 push $0x08048327: e9 e0 ff ff ff jmp 804830c <_init+0x30>0804832c <__libc_start_main@plt>:804832c: ff 25 04 a0 04 08 jmp *0x804a0048048332: 68 08 00 00 00 push $0x88048337: e9 d0 ff ff ff jmp 804830c <_init+0x30>0804833c <puts@plt>:804833c: ff 25 08 a0 04 08 jmp *0x804a0088048342: 68 10 00 00 00 push $0x108048347: e9 c0 ff ff ff jmp 804830c <_init+0x30>0804834c <exit@plt>:804834c: ff 25 0c a0 04 08 jmp *0x804a00c8048352: 68 18 00 00 00 push $0x188048357: e9 b0 ff ff ff jmp 804830c <_init+0x30>Disassembly of section .text:08048360 <_start>:8048360: 31 ed xor %ebp,%ebp8048362: 5e pop %esi8048363: 89 e1 mov %esp,%ecx8048365: 83 e4 f0 and $0xfffffff0,%esp8048368: 50 push %eax8048369: 54 push %esp804836a: 52 push %edx804836b: 68 40 84 04 08 push $0x80484408048370: 68 50 84 04 08 push $0x80484508048375: 51 push %ecx8048376: 56 push %esi8048377: 68 14 84 04 08 push $0x8048414804837c: e8 ab ff ff ff call 804832c <__libc_start_main@plt>8048381: f4 hlt 8048382: 90 nop8048383: 90 nop8048384: 90 nop8048385: 90 nop8048386: 90 nop8048387: 90 nop8048388: 90 nop8048389: 90 nop804838a: 90 nop804838b: 90 nop804838c: 90 nop804838d: 90 nop804838e: 90 nop804838f: 90 nop08048390 <__do_global_dtors_aux>:8048390: 55 push %ebp8048391: 89 e5 mov %esp,%ebp8048393: 53 push %ebx8048394: 83 ec 04 sub $0x4,%esp8048397: 80 3d 18 a0 04 08 00 cmpb $0x0,0x804a018804839e: 75 3f jne 80483df <__do_global_dtors_aux+0x4f>80483a0: a1 1c a0 04 08 mov 0x804a01c,%eax80483a5: bb 18 9f 04 08 mov $0x8049f18,%ebx80483aa: 81 eb 14 9f 04 08 sub $0x8049f14,%ebx80483b0: c1 fb 02 sar $0x2,%ebx80483b3: 83 eb 01 sub $0x1,%ebx80483b6: 39 d8 cmp %ebx,%eax80483b8: 73 1e jae 80483d8 <__do_global_dtors_aux+0x48>80483ba: 8d b6 00 00 00 00 lea 0x0(%esi),%esi80483c0: 83 c0 01 add $0x1,%eax80483c3: a3 1c a0 04 08 mov %eax,0x804a01c80483c8: ff 14 85 14 9f 04 08 call *0x8049f14(,%eax,4)80483cf: a1 1c a0 04 08 mov 0x804a01c,%eax80483d4: 39 d8 cmp %ebx,%eax80483d6: 72 e8 jb 80483c0 <__do_global_dtors_aux+0x30>80483d8: c6 05 18 a0 04 08 01 movb $0x1,0x804a01880483df: 83 c4 04 add $0x4,%esp80483e2: 5b pop %ebx80483e3: 5d pop %ebp80483e4: c3 ret 80483e5: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi80483e9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi080483f0 <frame_dummy>:80483f0: 55 push %ebp80483f1: 89 e5 mov %esp,%ebp80483f3: 83 ec 18 sub $0x18,%esp80483f6: a1 1c 9f 04 08 mov 0x8049f1c,%eax80483fb: 85 c0 test %eax,%eax80483fd: 74 12 je 8048411 <frame_dummy+0x21>80483ff: b8 00 00 00 00 mov $0x0,%eax8048404: 85 c0 test %eax,%eax8048406: 74 09 je 8048411 <frame_dummy+0x21>8048408: c7 04 24 1c 9f 04 08 movl $0x8049f1c,(%esp)804840f: ff d0 call *%eax8048411: c9 leave 8048412: c3 ret 8048413: 90 nop08048414 <main>:8048414: 55 push %ebp8048415: 89 e5 mov %esp,%ebp8048417: 83 e4 f0 and $0xfffffff0,%esp804841a: 83 ec 10 sub $0x10,%esp804841d: c7 04 24 00 85 04 08 movl $0x8048500,(%esp)8048424: e8 13 ff ff ff call 804833c <puts@plt>8048429: c7 04 24 00 00 00 00 movl $0x0,(%esp)8048430: e8 17 ff ff ff call 804834c <exit@plt>8048435: 90 nop8048436: 90 nop8048437: 90 nop8048438: 90 nop8048439: 90 nop804843a: 90 nop804843b: 90 nop804843c: 90 nop804843d: 90 nop804843e: 90 nop804843f: 90 nop08048440 <__libc_csu_fini>:8048440: 55 push %ebp8048441: 89 e5 mov %esp,%ebp8048443: 5d pop %ebp8048444: c3 ret 8048445: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi8048449: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi08048450 <__libc_csu_init>:8048450: 55 push %ebp8048451: 89 e5 mov %esp,%ebp8048453: 57 push %edi8048454: 56 push %esi8048455: 53 push %ebx8048456: e8 4f 00 00 00 call 80484aa <__i686.get_pc_thunk.bx>804845b: 81 c3 99 1b 00 00 add $0x1b99,%ebx8048461: 83 ec 1c sub $0x1c,%esp8048464: e8 73 fe ff ff call 80482dc <_init>8048469: 8d bb 18 ff ff ff lea -0xe8(%ebx),%edi804846f: 8d 83 18 ff ff ff lea -0xe8(%ebx),%eax8048475: 29 c7 sub %eax,%edi8048477: c1 ff 02 sar $0x2,%edi804847a: 85 ff test %edi,%edi804847c: 74 24 je 80484a2 <__libc_csu_init+0x52>804847e: 31 f6 xor %esi,%esi8048480: 8b 45 10 mov 0x10(%ebp),%eax8048483: 89 44 24 08 mov %eax,0x8(%esp)8048487: 8b 45 0c mov 0xc(%ebp),%eax804848a: 89 44 24 04 mov %eax,0x4(%esp)804848e: 8b 45 08 mov 0x8(%ebp),%eax8048491: 89 04 24 mov %eax,(%esp)8048494: ff 94 b3 18 ff ff ff call *-0xe8(%ebx,%esi,4)804849b: 83 c6 01 add $0x1,%esi804849e: 39 fe cmp %edi,%esi80484a0: 72 de jb 8048480 <__libc_csu_init+0x30>80484a2: 83 c4 1c add $0x1c,%esp80484a5: 5b pop %ebx80484a6: 5e pop %esi80484a7: 5f pop %edi80484a8: 5d pop %ebp80484a9: c3 ret 080484aa <__i686.get_pc_thunk.bx>:80484aa: 8b 1c 24 mov (%esp),%ebx80484ad: c3 ret 80484ae: 90 nop80484af: 90 nop080484b0 <__do_global_ctors_aux>:80484b0: 55 push %ebp80484b1: 89 e5 mov %esp,%ebp80484b3: 53 push %ebx80484b4: 83 ec 04 sub $0x4,%esp80484b7: a1 0c 9f 04 08 mov 0x8049f0c,%eax80484bc: 83 f8 ff cmp $0xffffffff,%eax80484bf: 74 13 je 80484d4 <__do_global_ctors_aux+0x24>80484c1: bb 0c 9f 04 08 mov $0x8049f0c,%ebx80484c6: 66 90 xchg %ax,%ax80484c8: 83 eb 04 sub $0x4,%ebx80484cb: ff d0 call *%eax80484cd: 8b 03 mov (%ebx),%eax80484cf: 83 f8 ff cmp $0xffffffff,%eax80484d2: 75 f4 jne 80484c8 <__do_global_ctors_aux+0x18>80484d4: 83 c4 04 add $0x4,%esp80484d7: 5b pop %ebx80484d8: 5d pop %ebp80484d9: c3 ret 80484da: 90 nop80484db: 90 nopDisassembly of section .fini:080484dc <_fini>:80484dc: 55 push %ebp80484dd: 89 e5 mov %esp,%ebp80484df: 53 push %ebx80484e0: 83 ec 04 sub $0x4,%esp80484e3: e8 00 00 00 00 call 80484e8 <_fini+0xc>80484e8: 5b pop %ebx80484e9: 81 c3 0c 1b 00 00 add $0x1b0c,%ebx80484ef: e8 9c fe ff ff call 8048390 <__do_global_dtors_aux>80484f4: 59 pop %ecx80484f5: 5b pop %ebx80484f6: c9 leave 80484f7: c3 ret deepfuture@deepfuture-laptop:~/private/mytest$ gcc -c hello.chello.c: In function ‘main’:hello.c:4: warning: incompatible implicit declaration of built-in function ‘exit’deepfuture@deepfuture-laptop:~/private/mytest$ objdump -d hello.ohello.o: file format elf32-i386Disassembly of section .text:00000000 <main>:0:55 push %ebp1:89 e5 mov %esp,%ebp3:83 e4 f0 and $0xfffffff0,%esp6:83 ec 10 sub $0x10,%esp9:c7 04 24 00 00 00 00 movl $0x0,(%esp)10:e8 fc ff ff ff call 11 <main+0x11>15:c7 04 24 00 00 00 00 movl $0x0,(%esp)1c:e8 fc ff ff ff call 1d <main+0x1d>deepfuture@deepfuture-laptop:~/private/mytest$
char*與char[]-從編譯后的匯編代碼分析
節(jié) 含義
.text 已編譯程序的機器代碼
.rodata 只讀數(shù)據(jù),如pintf和switch語句中的字符串和常量值
.data 已初始化的全局變量
.bss 未初始化的全局變量
.symtab 符號表,存放在程序中被定義和引用的函數(shù)和全局變量的信息
.rel.text 當鏈接器吧這個目標文件和其他文件結合時,.text節(jié)中的信息需修改
.rel.data 被模塊定義和引用的任何全局變量的信息
.debug 一個調試符號表。
.line 原始C程序的行號和.text節(jié)中機器指令之間的映射
.strtab 一個字符串表,其內容包含.systab和.debug節(jié)中的符號表
1、匯編相關段 的說明在上。
2、C源代碼,x為char *,y為char []
#include <stdio.h>void main(){char *x="xxxx";char y[]="yy";//y的16進制ASCII碼是97,9797的十進制為31097printf("%s-----%s",x,y);exit(0);}$ gcc -S testcr.c
.file "testcr.c".section .rodata.LC0:.string "xxxx"#使用char *分配.LC1:.string "%s-----%s".text.globl main.type main, @functionmain:pushl %ebpmovl %esp, %ebpandl $-16, %espsubl$32, %esp#分配32字節(jié)??臻g,根據(jù)變量情況分配movl$.LC0, 24(%esp)#x變量使用指針(4個字節(jié)大小),放入棧中,可以看到,變量分配靠近??臻g的尾部movw$31097, 29(%esp)#字符'yy'移到main程序的棧中,直接將y變量的值放入棧中movb$0, 31(%esp)#加上NULL標志,表示字符結束 movl $.LC1, %eaxleal 29(%esp), %edxmovl %edx, 8(%esp)movl 24(%esp), %edxmovl %edx, 4(%esp)movl %eax, (%esp)call printfmovl $0, (%esp)call exit.size main, .-main.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3".section .note.GNU-stack,"",@progbits3、由以上分析可以看出,在MAIN函數(shù)中char *分配在只讀數(shù)據(jù)段中,實際使用時,只在程序棧中分配一個指針的空間。char[] 在程序棧中分配空間,然后直接使用movl、movw之類的匯編直接把值放入棧中空間。那么在其它函數(shù)中聲明的呢,可以從以下程序中看出,仍然如此。
#include <stdio.h>void myprinf(){char *x="xxxx";char y[]="yy";//y的16進制ASCII碼是97,9797的十進制為31097printf("%s-----%s",x,y);}void main(){int num=1;myprint();exit(0);}$ gcc -S testcr.c
ASM代碼:
.file "testcr.c".section .rodata.LC0:.string"xxxx".LC1:.string "%s-----%s".text.globl myprinf.type myprinf, @functionmyprinf:pushl %ebpmovl %esp, %ebpsubl $40, %espmovl$.LC0, -16(%ebp)movw$31097, -11(%ebp)movb$0, -9(%ebp)movl $.LC1, %eaxleal -11(%ebp), %edxmovl %edx, 8(%esp)movl -16(%ebp), %edxmovl %edx, 4(%esp)movl %eax, (%esp)call printfleaveret.size myprinf, .-myprinf.globl main.type main, @functionmain:pushl %ebpmovl %esp, %ebpandl $-16, %espsubl $32, %espmovl $1, 28(%esp)call myprintmovl $0, (%esp)call exit.size main, .-main.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3".section .note.GNU-stack,"",@progbits總結
以上是生活随笔為你收集整理的C指针原理(20)-C指针基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS中的prototype、__prot
- 下一篇: Logback介绍及入门