C指針原理(46)-C應用技巧(1)
#include <stdio>? int main(void)? {? ? ? ? int i=0; ? ? ? char string[100]; ? ? ? strcpy(string,"abcdefghijklmnopqrstuvwxyz"); ? ?while (string[i]!=‘\0‘){ //將小寫轉化成大寫 ? ? ? ? ? ? ? if (islower(string[i])) ?? ? ? ? ? ? ? ? ? ? string[i]=toupper(string[i]);? ? ? ? ? ?i++;? ? ?}? ? ?printf("%s\n",string);? ? ?return 0;? }
linux-C獲得用戶信息和節點信息
C代碼 ?
#include <unistd.h> ? #include <sys/utsname.h> ? #include <sys/types.h> ? #include <pwd.h> ? int main(void){// ? ? ? char hname[256];//節點名稱 ? ? ? ?struct utsname uts;//節點結構信 ? ? ? uid_t uid; ? ? ? gid_t gid; ? ? ? ? ? ? ?struct passwd *pw; ? ?? ? ? ?if (gethostname(hname,255)!=0||uname(&uts)<0){ ? ? ? ? ?printf("不能得到主機信息"); ? ? ? ? ? ? ? ? ? ? exit(1); ? ? ? ? ? ?} ? ?? ? printf("主機名:%s\n",hname); ? ? printf("系統名稱:%s\n 機器名稱:%s\n",uts.sysname,uts.machine); ? ? printf("節點名稱:%s\n",uts.nodename); ? ? printf("版本:%s,版本號%s",uts.release,uts.version);//系統版本,版本號 ? ? ? //取得當前用戶登陸情況 ? ? ? ?uid=getuid(); ? ? ? ?gid=getgid(); ? ? ? ?pw=getpwuid(uid); ? ? ? ?printf("用戶id 為%d,用戶組為%d\n",uid,gid); ? ? ? ?printf("用戶真實姓名%s\n用戶名稱:%s\n",pw->pw_gecos,pw->pw_name); ? ? ? ?printf("用戶uid:%s\ngid:%s\n",pw->pw_uid,pw->pw_gid); ? ? ? ? ? ?? ? ? ?printf("主目錄:%s\n",pw->pw_dir); ? ? ? ? ? ? ?? ? ? ?printf("用戶shell:%s\n",pw->pw_shell); ? ? ?? ?? } ?
?運行:
gcc -o test7 test7.c
test7.c: In function ‘main’:
test7.c:13: warning: incompatible implicit declaration of built-in function ‘printf’
test7.c:14: warning: incompatible implicit declaration of built-in function ‘exit’
test7.c:17: warning: incompatible implicit declaration of built-in function ‘printf’
./test7
主機名:puppypc
系統名稱:Linux
?機器名稱:i686
節點名稱:puppypc
版本:2.6.30.5,版本號#1 SMP Tue Sep 1 15:48:26 GMT-8 2009用戶id 為0,用戶組為0
用戶真實姓名root
用戶名稱:root
用戶uid:(null)
gid:(null)
主目錄:/root
用戶shell:/bin/sh
用戶密碼:x
#
linux-C產生臨時文件
#include <stdio.h>
int main(void){
? ?char tmpname[L_tmpnam];
? ?char *filename;
? ?FILE *fp;
? ?strcpy(tmpname,"/tmp/dfXXXXXX");//file name:df...
? ?filename=mktemp(tmpname);//generate tempfile
? ?printf("temporary file name:%s\n",filename);
? ?
? ?fp=tmpfile();
? ?if (fp) printf("temporary file oepn.\n");
? ?else perror("error");
? ?exit(0); ?
}
linux-文件屬性及目錄基本操作
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
int main(int argc,char *argv[]){
? ?int i;
? ?struct stat buf;
? ?char *ptr;
? ?if (argc<2){
? ? ? ?printf("filename error");
? ? ? ?exit(1);
? ?}
? ?if (lstat(argv[1],&buf)<0){//lstat和stat 判斷文件屬性,但lstat只判斷連接文件本身,不追蹤真實文件
? ? ? ?perror("lstat error");
? ?}
? ?if (S_ISREG(buf.st_mode)) ptr="普通文件";
? ?else if(S_ISDIR(buf.st_mode)) ptr="目錄";
? ?else if(S_ISCHR(buf.st_mode)) ptr="字符設備";
? ?else if(S_ISFIFO(buf.st_mode)) ptr="有名管道";
? ?else if(S_ISLNK(buf.st_mode)) ptr="符號鏈接";
? ?else if(S_ISBLK(buf.st_mode)) ptr="塊設備";
? ?else if(S_ISSOCK(buf.st_mode)) ptr="SOCKET";
? ?else ptr="未知設備";
? ?printf("FILE %s is %s file",argv[1],ptr);
? ?if (S_ISREG(buf.st_mode)){//如果是文件名
? ? ? ?printf("file size is %d bytes.\n",buf.st_size);
? ?}
? ?if (S_ISDIR(buf.st_mode)){//如果是目錄名,則ls目錄的文件
? ? ? ?DIR *dp;
? ? ? ?struct dirent *dirp;
? ? ? ?if ((dp=opendir(argv[1]))==NULL) perror("opendir error");
? ? ? ?while ((dirp=readdir(dp))!=NULL){
? ? ? ? ? printf("%s\n",dirp->d_name); ? //輸出目錄下的文件名
? ? ? ?}
? ? ? ? ? closedir(dp);
? ? ? ? ? free(dirp);
? ?}
? ?return 0;
}
c-文件操作-文件位置
CC++C#FP
long file_pos=ftell(fp);//返回當前文件位置
fgetpos(fp,&fp_pos);//返回當前文件位置到fp_pos中
fsetpos(fp,&fp_pos);//設置當前文件位置為fp_pos
rewind(fp);//把文件置在起始處
linux-多線程-互斥鎖在多進程共享
C代碼 ?
#include <sys/stat.h> ?
#include <fcntl.h> ?
#include <sys/mman.h> ?
#include <unistd.h> ?
??
??
#include <pthread.h> ?
#include <stdio.h> ?
#include <stdlib.h> ?
??
??
??
??
int main(void){//2個進程,一個進程完成每次加1,另一個進程完成每次加2,2個進程協作完成累加,使用共享內存方式在進程間通信 ?
??
int *x; ?
int rt; ?
int shm_id; ?
char *addnum="myadd"; ?
char *ptr; ?
??
pthread_mutex_t mutex;//互斥對象 ?
pthread_mutexattr_t mutexattr;//互斥對象屬性 ?
??
??
? ?pthread_mutexattr_init(&mutexattr);//初始化互斥對象屬性 ?
? ?pthread_mutexattr_setpshared(&mutexattr,PTHREAD_PROCESS_SHARED);//設置互斥對象為PTHREAD_PROCESS_SHARED共享,即可以在多個進程的線程訪問,PTHREAD_PROCESS_PRIVATE為同一進程的線程共享 ?
? ?rt=fork();//復制父進程,並創建子進程 ??
//deepfuture.iteye.com,深未來技術原創 ?
? ?if (rt==0){//子進程完成x+1 ?
? ? ? ?shm_id=shm_open(addnum,O_RDWR,0); ?
? ? ? ?ptr=mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);/*連接共享內存區*/ ?
? ? ? ?x=(int *)ptr; ? ?
? ??
? ? ? for (int i=0;i<10;i++){//加10次。相當於加10 ?
? ? ? ?pthread_mutex_lock(&mutex); ? ? ? ?
? ? ? ?(*x)++; ?
? ? ? ?printf("x++:%d\n",*x); ?
? ? ? ?pthread_mutex_unlock(&mutex); ??
? ? ? ?sleep(1); ? ? ? ? ? ? ? ? ??
? ? ? } ?
? ?} ? ??
? ?else{//父進程完成x+2 ?
? ? ? ?shm_id=shm_open(addnum,O_RDWR|O_CREAT,0644); ?
? ? ? ? ftruncate(shm_id,sizeof(int)); ?
? ? ? ? ptr=mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);/*連接共享內存區*/ ?
? ? ? ? x=(int *)ptr; ??
? ? ? ? ? ??
? ? ? for (int i=0;i<10;i++){//加10次,相當於加20 ?
? ? ? ?pthread_mutex_lock(&mutex); ? ? ? ??
? ? ? ?(*x)+=2; ?
? ? ? ?printf("x+=2:%d\n",*x); ?
? ? ? ?pthread_mutex_unlock(&mutex); ? ?
? ? ? ?sleep(1); ??
? ? ? } ? ? ? ?
? ? ? ??
? ?} ??
? ?shm_unlink(addnum);//刪除共享名稱 ?
? ?munmap(ptr,sizeof(int));//刪除共享內存 ?
? ?return(0); ?
} ?
?編譯
deepfuture@deepfuture-laptop:~/private/mytest$ gcc ?-lpthread -std=c99 -lrt -o testmutex testmutex.c
執行
deepfuture@deepfuture-laptop:~/private/mytest$ ./testmutex
x+=2:2
x++:3
x+=2:5
x++:6
x+=2:8
x++:9
x+=2:11
x++:12
x+=2:14
x++:15
x+=2:17
x++:18
x+=2:20
x++:21
x+=2:23
x++:24
x+=2:26
x++:27
x+=2:29
x++:30
一、什麽是共享內存區
共享內存區是最快的可用IPC形式。它允許多個不相關的進程去訪問同一部分邏輯內存。如果需要在兩個運行中的進程之間傳輸數據,共享內存將是一種效率極高的解決方案。一旦這樣的內存區映射到共享它的進程的地址空間,這些進程間數據的傳輸就不再涉及內核。這樣就可以減少系統調用時間,提高程序效率。
共享內存是由IPC為一個進程創建的一個特殊的地址範圍,它將出現在進程的地址空間中。其他進程可以把同一段共享內存段“連接到”它們自己的地址空間裏去。所有進程都可以訪問共享內存中的地址。如果一個進程向這段共享內存寫了數據,所做的改動會立刻被有訪問同一段共享內存的其他進程看到。
要註意的是共享內存本身沒有提供任何同步功能。也就是說,在第一個進程結束對共享內存的寫操作之前,並沒有什麽自動功能能夠預防第二個進程開始對它進行讀操作。共享內存的訪問同步問題必須由程序員負責。可選的同步方式有互斥鎖、條件變量、讀寫鎖、紀錄鎖、信號燈。
二、mmap
在講共享內存前我們要先來介紹下面幾個函數。
mmap函數把一個文件或一個Posix共享內存區對象映射到調用進程的地址空間。使用該函數有三個目的:
1.使用普通文件以提供內存映射I/O
2.使用特殊文件以提供匿名內存映射。
3.使用shm_open以提供無親緣關系進程間的Posix共享內存區。
函數1.
名稱:: mmap
功能: 把I/O文件映射到一個存儲區域中
頭文件: #include <sys/mman.h>
函數原形:
void mmap(void addr,size_t len,int prot,int flag,int filedes,off_t off);
參數:
addr????? 指向映射存儲區的起始地址
len?????? 映射的字節
prot????? 對映射存儲區的保護要求
flag????? flag標誌位
filedes??? 要被映射文件的描述符
off?????? 要映射字節在文件中的起始偏移量
返回值:
若成功則返回映射區的起始地址,若出錯則返回MAP_FAILED
addr參數用於指定映射存儲區的起始地址。通常將其設置為NULL,這表示由系統選擇該映射區的起始地址。
filedes指要被映射文件的描述符。在映射該文件到一個地址空間之前,先要打開該文件。len是映射的字節數。
off是要映射字節在文件中的起始偏移量。通常將其設置為0。
prot參數說明對映射存儲區的保護要求。可將prot參數指定為PROT_NONE,或者是PROT_READ(映射區可讀),PROT_WRITE(映射區可寫),PROT_EXEC(映射區可執行)任意組合的按位或,也可以是PROT_NONE(映射區不可訪問)。對指定映射存儲區的保護要求不能超過文件open模式訪問權限。
flag參數影響映射區的多種屬性:
MAP_FIXED 返回值必須等於addr.因為這不利於可移植性,所以不鼓勵使用此標誌。
MAP_SHARED 這一標誌說明了本進程對映射區所進行的存儲操作的配置。此標誌指定存儲操作修改映射文件。
MAP_PRIVATE 本標誌導致對映射區建立一個該映射文件的一個私有副本。所有後來對該映射區的引用都是引用該副本,而不是原始文件。
要註意的是必須指定MAP_FIXED或MAP_PRIVATE標誌其中的一個,指定前者是對存儲映射文件本身的一個操作,而後者是對其副本進行操作。
mmap成功返回後,fd參數可以關閉。該操作對於由mmap建立的映射關系沒有影響。為從某個進程的地址空間刪除一個映射關系,我們調用munmap.
函數2.
名稱:: munmap
功能: 解除存儲映射
頭文件: #include <sys/mman.h>
函數原形: int munmap(caddr_t addr,size_t len);
參數:
addr????? 指向映射存儲區的起始地址
len?????? 映射的字節
返回值: 若成功則返回0,若出錯則返回-1
其中addr參數是由mmap返回的地址,len是映射區的大小。再次訪問這些地址導致向調用進程產生一個SIGSEGV信號。
如果被映射區是使用MAP_PRIVATE標誌映射的,那麽調用進程對它所作的變動都被丟棄掉。
內核的虛存算法保持內存映射文件(一般在硬盤上)與內存映射區(在內存中)的同步(前提它是MAP_SHARED內存區)。這就是說,如果我們修改了內存映射到某個文件的內存區中某個位置的內容,那麽內核將在稍後某個時刻相應地更新文件。然而有時候我們希望確信硬盤上的文件內容與內存映射區中的文件內容一致,於是調用msync來執行這種同步。
函數3.
名稱:: msync
功能: 同步文件到存儲器
頭文件: #include <sys/mman.h>
函數原形: int msync(void addr,size_t len,int flags);
參數:
addr????? 指向映射存儲區的起始地址
len?????? 映射的字節
prot????? flags
返回值: 若成功則返回0,若出錯則返回-1
其中addr和len參數通常指代內存中的整個內存映射區,不過也可以指定該內存區的一個子集。flags參數為MS_ASYNC(執行異步寫),MS_SYNC(執行同步寫),MS_INVALIDATE(使高速緩存的數據實效)。其中MS_ASYNC和MS_SYNC這兩個常值中必須指定一個,但不能都指定。它們的差別是,一旦寫操作已由內核排入隊列,MS_ASYNC即返回,而MS_SYNC則要等到寫操作完成後才返回。如果還指定了MS_INVALIDATE,那麽與其最終拷貝不一致的文件數據的所有內存中拷貝都失效。後續的引用將從文件取得數據。
函數4.
名稱:: memcpy
功能: 復制映射存儲區
頭文件: #include <string.h>
函數原形: void memcpy(void dest,const void src,size_t n);
參數:
dest?????? 待復制的映射存儲區
src??????? 復制後的映射存儲區
n????????? 待復制的映射存儲區的大小
返回值:
返回dest的首地址
memcpy拷貝n個字節從dest到src。
下面就是利用mmap函數影射I/O實現的cp命令。
/*mycp.c*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc,char *argv[])
{
int fdin,fdout;
void *arc,dst;
struct stat statbuf;
if(argc!=3)
{
printf(“please input two file!\n”);
exit(1);
}
if((fdin=open(argv[1],O_RDONLY))<0) /*打開原文件*/
perror(argv[1]);
if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC))<0)/*創建並打開目標文件*/
perror(argv[2]);
if(fstat(fdin,&statbuf)<0) /*獲得文件大小信息*/
printf(“fstat error”);
if(lseek(fdout,statbuf.st_size-1,SEEK_SET)==-1)/*初始化輸出映射存儲區*/
printf(“lseek error”);
if(write(fdout,”1”)!=1)
printf(“write error”);
if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED)
/*映射原文件到輸入的映射存儲區*/
printf(“mmap error);
if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0)) ==MAP_FAILED) /*映射目標文件到輸出的映射存儲區*/
printf(“mmap error);
memcpy(dst,src,statbuf.st_size);/*復制映射存儲區*/
munmap(src,statbuf.st_size); /*解除輸入映射*/
munmap(dst,statbuf.st_size); /*解除輸出映射*/
close(fdin);``
close(fdout);
}
下面是運行結果:
#cc –o mycp mycp.c
#./mycp test1 test2
三、posix共享內存函數
posix共享內存區涉及兩個步驟:
1、指定一個名字參數調用shm_open,以創建一個新的共享內存區對象或打開一個已存在的共享內存區對象。
2、調用mmap把這個共享內存區映射到調用進程的地址空間。傳遞給shm_open的名字參數隨後由希望共享該內存區的任何其他進程使用。
函數5.
名稱:: shm_open
功能: 打開或創建一個共享內存區
頭文件: #include <sys/mman.h>
函數原形: int shm_open(const char name,int oflag,mode_t mode);
參數:
name??? 共享內存區的名字
cflag??? 標誌位
mode??? 權限位
返回值: 成功返回0,出錯返回-1
oflag參數必須含有O_RDONLY和O_RDWR標誌,還可以指定如下標誌:O_CREAT,O_EXCL或O_TRUNC.
mode參數指定權限位,它指定O_CREAT標誌的前提下使用。
shm_open的返回值是一個整數描述字,它隨後用作mmap的第五個參數。
函數6.
名稱:: shm_unlink
功能: 刪除一個共享內存區
頭文件: #include <sys/mman.h>
函數原形: int shm_unlink(const char name);
參數: name??? 共享內存區的名字
返回值: 成功返回0,出錯返回-1
shm_unlink函數刪除一個共享內存區對象的名字,刪除一個名字僅僅防止後續的open,mq_open或sem_open調用取得成功。
示例:
下面是創建一個共享內存區的例子:
/shm_open.c創建共享內存區/
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc,char **argv)
{
int shm_id;
if(argc!=2)
{
printf(“usage:shm_open <pathname>\n”);
exit(1);
}
shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);
printf(“shmid:%d\n”,shm_id);
shm_unlink(argv[1]);
}
下面是運行結果,註意編譯程序我們要加上“-lrt”參數。
#cc –lrt –o shm_open shm_open.c
#./shm_open test
shm_id:3
四、ftruncate和fstat函數
普通文件或共享內存區對象的大小都可以通過調用ftruncate修改。
函數7.
名稱:: ftruncate
功能: 調整文件或共享內存區大小
頭文件: #include <unistd.h>
函數原形: int ftruncate(int fd,off_t length);
參數:
fd????????? 描述符
length?????? 大小
返回值: 成功返回0,出錯返回-1
當打開一個已存在的共享內存區對象時,我們可調用fstat來獲取有關該對象的信息。
函數8.
名稱:: fstat
功能: 獲得文件或共享內存區的信息
頭文件:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
函數原形: int stat(const char file_name,struct stat buf);
參數:
file_name????????? 文件名
buf?????????????? stat結構
返回值: 成功返回0,出錯返回-1
對於普通文件stat結構可以獲得12個以上的成員信息,然而當fd指代一個共享內存區對象時,只有四個成員含有信息。
struct stat{
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
};
/*shm_show.c顯示共享區信息*/
#include <unistd.h>
#include <sys/type.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc,char **argv)
{
int shm_id;
struct stat buf;
if(argc!=2)
{
printf(“usage:shm_open <pathname>\n”);
exit(1);
}
shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);/*創建共享內存*/
ftruncate(shm_id,100);/*修改共享內存的大小*/
fstat(shm_id,&buf); /*把共享內存的信息記錄到buf中*/
printf(“uid_t:%d\n”,buf.st_uid); /*共享內存區所有者ID*/
printf(“git_t:%d\n”,buf.st_gid); /*共享內存區所有者組ID*/
printf(“size :%d\n”,buf.st_size); /*共享內存區大小*/
}
下面是運行結果:
#cc –lrt –o shm_show shm_show.c
#./shm_show test
uid_t:0
git_t:0
size:100
鍵盤緩沖區殘余信息問題?
#include <stdio.h>
int main()
{
??? int a;``
??? char c;?
??? do
??? {
??????? scanf("%d",&a);
??????? scanf("%c",&c);
??????? printf("a=%d???? c=%c\n",a,c);
??????? /*printf("c=%d\n",c);*/
??? }while(c!=‘‘N‘‘);
}?
?? scanf("%c",&c);這句不能正常接收字符,什麽原因呢?我們用printf("c=%d\n",c);將C用int表示出來,啟用printf("c=%d\n",c);這一句,看看scanf()函數賦給C到底是什麽,結果是 c=10 ,ASCII值為10是什麽?換行即\n.對了,我們每擊打一下"Enter"鍵,向鍵盤緩沖區發去一個“回車”(\r),一個“換行"(\n),在這裏\r被scanf()函數處理掉了(姑且這麽認為吧^_^),而\n被scanf()函數“錯誤”地賦給了c.?
解決辦法:可以在兩個scanf()函數之後加個fflush(stdin);,還有加getch(); getchar();也可以,但是要視具體scanf()語句加那個,這裏就不分析了,讀者自己去摸索吧。但是加fflush(stdin);不管什麽情況都可行。?
函數名: fflush?
功 能: 清除一個流?
用 法: int fflush(FILE *stream);?
#include <stdio.h>
int main()
{
??? int a;
??? char c;?
??? do
??? {
??????? scanf("%d",&a);
??????? fflush(stdin);
??????? scanf("%c",&c);
??????? fflush(stdin);
??????? printf("a=%d???? c=%c\n",a,c);?
??? }while(c!=‘‘N‘‘);
}??????
這裏再給一個用“空格符”來處理緩沖區殘余信息的示例:?
運行出錯的程序:?
#include <stdio.h>
int main()
{
??? int i;
??? char j;
??? for(i = 0;i < 10;i++)
??? {
??????? scanf("%c",&j);/*這裏%前沒有空格*/
??? }
}?
使用了空格控制符後:?
#include <stdio.h>
int main()
{
??? int i;
??? char j;
??? for(i = 0;i < 10;i++)
??? {
??????? scanf(" %c",&j);/註意這裏%前有個空格/
??? }
}?
??? 可以運行看看兩個程序有什麽不同。?
???????高級版的取子串函數,可以完成正向取子串,反向取子串,
1、調用:
substr(取出的子串,源串,起始位置,長度)
函數返回實際取到子串的長度
其中長度可以為正數(從左邊向右邊取),長度為負數(從右邊向左邊取),長度可以超過實際能取到的子串長度,函數會智能判斷,取長度範圍內盡可能長的子串。
2、函數源代碼
C代碼 ?
int substr(char* dchr,char *schr,int begin,int len){ ?
//作者:[email protected]?
//取子串函數,dchr為取好後的子串,schr為源串,返回成功取出的子串數目,len為負數,則從begin向頭部移動(正向),否則向尾部移動(反向),begin為起始位置(從1開始),len為子串長度 ?
??
? ? int slen=0; ?
??
? ? int rc=0; ? ? ?
??
? ? if (begin<=0) begin=1;//起始位置為0時,會從1開始 ?
??
? ? slen=strlen(schr)-begin; ? ? ?
??
? ? if (slen<=0||len==0){//當len為0或begin的位置已經超過源串長度時,取空串 ?
??
? ? ? ?*dchr=NULL; ?
??
? ? ? ?return rc; ?
??
? ? } ?
??
? ? if (len<0){//len為負數,表示從begin處向頭部移動len個字符的子串,允許出現len移過頭的現象(begin=3,len=-6,則取從位置1到位置3的子串) ?
??
? ? ? ? len=-len; ?
??
? ? ? ? if(len>strlen(schr)) begin=1; ?
??
? ? ? ? else if((begin-len)<=0){ ?
??
? ? ? ? ? ? len=begin; ?
??
? ? ? ? ? ? begin=1; ?
??
? ? ? ? } ?
??
? ? ? ? else { ?
??
? ? ? ? ? ? ?begin-=len; ?
??
? ? ? ? ? ? ?begin++; ?
??
? ? ? ? } ?
??
? ? } ?
??
??
??
? ? ?begin--; ?
??
? ? ?schr+=begin; ?
??
? ? ?int i=0; ?
??
? ? ?for(i=0;i<len&&*schr!=0;i++){ ?
??
? ? ? ? *dchr++ = *schr++; ? ? ? ? ??
??
? ? ?} ?
??
? ? ?*dchr=0; ??
??
? ? ?rc=i; ?
??
? return rc; ?
??
}
c_預定義宏-反映編譯信息
??
1、???? LINE:被編譯的文件中的行號
2、???? FILE:編譯的日期
3、???? DATE:編譯的日期("Mm dd yyyy")
4、???? TIME:編譯的時間("hh:mm:ss")
5、???? STDC:如果編譯器符合C標準(C89或C99),則值為1
C-#line和#error
1、
1)源代碼:
test2.c
C代碼 ?
#line 1 ?
int main(void){ ?
printf("line 1\n"); ?
printf("line 2\n"); ?
printf("line 3\n"); ?
printf("line 4\n"); ?
printf("line 5\n"); ?
printf("line 6\n"); ?
printf("line 7\n"); ?
printf("line 8\n"); ?
#include "test1.c ?
?test1.c
?
C代碼 ?
#line 9 "test2.c" ?
#define LINUX ?
#ifdef WIN32 ?
? printf("win32\n"); ? ??
#elif defined LINUX ?
? printf("linux %d %s\n",__LINE__,__FILE__); ? ? ? ? ?
#else ?
? #error no flag define ??
? //如果LINUX和WIN32沒有定義,#error會顯示錯誤信息,然後停止編譯 ?
#endif ?
} ?
? 2)運行結果:
mysea@mysea-pc:~/test$ ./test2
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
linux 13 test2.c
?
2、#error表示停止編譯,顯示錯誤信息
3、#line 直接指定下一行的行號及文件名
1)指定行號
#line n
2)指定文件名和行號
#line n "filename"
4、源代碼的#include "test1.c"和#line 9 "test2.c"表示:test2.c和test1.c實質屬於一個C程序:test2。
1)註意這只是標註,如果要在編譯時把test1.c包括進來,必須加上#include "test1.c
?
?
2)編譯時,編譯test2
?
?
?
mysea@mysea-pc:~/test$ gcc -o test2 test2.c
?
C指針原理(46)-C應用技巧(1)