1. 程式人生 > >C語言常見的函式呼叫

C語言常見的函式呼叫

C語言常見的函式呼叫

isatty,函式名,主要功能是檢查裝置型別,判斷檔案描述詞是否為終端機。

函式名: isatty

用 法: int isatty(int desc);

返回值:如果引數desc所代表的檔案描述詞為一終端機則返回1,否則返回0。

程式例:

#include <stdio.h>

#include <io.h>

int main(void)

{

int handle;

handle = fileno(stdout);

if (isatty(handle))

printf("Handle %d is a device type\n", handle);

else

printf("Handle %d isn't a device type\n", handle);

re

 

 

函式名稱:fileno(在VC++6.0下為_fileno)

函式原型:int _fileno( FILE *stream );

函式功能:fileno()用來取得引數stream指定的檔案流所使用的檔案描述符

返回值:某個資料流的檔案描述符

標頭檔案:stdio.h

相關函式:open,fopen,fclose

 

void *memset(void *s, int ch, size_t n);

函式解釋:將s中當前位置後面的n個位元組 (typedef unsigned int size_t )用 ch 替換並返回 s 。

memset:作用是在一段記憶體塊中填充某個給定的值,它是對較大的結構體陣列進行清零操作的一種最快方法

 

 

函式原型

char *fgets(char *buf, int bufsize, FILE *stream);

引數

*buf: 字元型指標,指向用來儲存所得資料的地址。

bufsize: 整型資料,指明儲存資料的大小。

*stream: 檔案結構體指標,將要讀取的檔案流。

返回值

  1. 成功,則返回第一個引數buf;
  2. 在讀字元時遇到end-of-file,則eof指示器被設定,如果還沒讀入任何字元就遇到這種情況,則buf保持原來的內容,返回NULL;
  3. 如果發生讀入錯誤,error指示器被設定,返回NULL,buf的值可能被改變。

chdirC語言中的一個系統呼叫函式(同cd),用於改變當前工作目錄,其引數為Path 目標目錄,可以是絕對目錄或相對目錄。

 

 

exec函式

linux下c語言程式設計exec函式使用

2012年04月10日 09:39:27

閱讀數:19800

exec用被執行的程式完全替換呼叫它的程式的影像。fork建立一個新的程序就產生了一個新的PID,exec啟動一個新程式,替換原有的程序,因此這個新的被exec執行的程序的PID不會改變,和呼叫exec函式的程序一樣。

  下面來看下exec函式族:

  #include <uniSTd.h>

  int execl(cONst char *path, const char *arg, ...);

  int execlp(const char *file, const char *arg, ...);

  int execle(const char *path, const char *arg, ..., char *const envp[]);

  int execv(const char *path, char *const argv[]);

  int execvp(const char *file, char *const argv[]);

  int execve(const char *path, char *const argv[], char *const envp[]);

  exec函式族裝入並執行程式pathname,並將引數arg0(arg1,arg2,argv[],envp[])傳遞給子程式,出錯返回-1。在exec函式族中,字尾l、v、p、e新增到exec後,所指定的函式將具有某種操作能力有後綴:

execl("/bin/ls","ls","-a",NULL)

execv("/bin/ls",arg)

execlp("ls","ls","-a",NULL)

execvp("ls",arg)

execle("/bin/ls","ls","-a",NULL,envp)

execve("/bin/ls",arg,envp)

 

 

assert()使用

  assert()是一個除錯程式時經常使用的巨集,在程式執行時它計算括號內的表示式,如果表示式為FALSE (0), 程式將報告錯誤,並終止執行。如果表示式不為0,則繼續執行後面的語句,它的作用是終止程式以免導致嚴重後果,同時也便於查詢錯誤

linux程式設計之dup與dup2

在linux下,通過open開啟以檔案後,會返回一個檔案描述符,檔案描述符會指向一個檔案表,檔案表中的節點指標會指向節點表。看下圖:

開啟檔案的核心資料結構

dup和dup2兩個函式都可以用來複制開啟的檔案描述符,複製成功後和複製源共享同一個檔案表。看下錶

執行dup後的核心資料結構

dup函式

fd1=dup(fd)

fd1和fd共享一個檔案表(對df進行什麼操作,fd1也會有相應的操作,fd和fd1是同步的)

具體解釋:

   

#inclue<stdio.h>

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

#include<stdlib.h>

int main()

{

char buf[6]={0};

char buf1[6]={0};

int fd = open("file",O_RDWR|O_CREAT,0644);

if(fd < 0)

printf("open error");

printf("fd:%d\n",fd);

//輸出fd=3;

write(fd,"hello,world",12);

lseek(fd,0,SEEK_SET);  //將檔案偏移量置為0,就是從第一個字元開始讀(h開始)

read(fd,buf,5);

printf("fd:%s",buf);//輸出hello

int fd1 = dup(fd);

read(fd1,buf1,5); //之前做的是對fd的讀寫操作,並沒有對fd1做任何操作。但在這對fd1進行了讀,如果輸出資料。說明fd和fd1是同步的(fd做了什麼相當於fd1也做了什麼)

printf("fd1:%s\n",buf1); //輸出,worl

//既然輸出的是fd中的內容,說明fd和fd1共用一個檔案表,讀到的是,worl,而不是hello(我們在上面將偏移量從第一個字元開始,輸出hello之後,fd的偏移量距離開始有5個字元當我們再次讀fd的時候,它是從第6個字元開始讀的,很明顯,第6個是逗號,往後讀5個,就是,worl),說明偏移量是一致的。(其實不用寫偏移量,因為共用檔案表就意味著檔案偏移量也共用)

printf("fd1:%d\n",fd1);//輸出fd1 = 4

//fd=3不等於fd1說明不共用同一個檔案描述符。這也是dup和dup2的區別。

close(fd);

close(fd1);

return 0;

}

(2)dup2函式

   

fd2 = dup2(fd,fd1);

fd2用的fd1(第二個引數)的描述符,用的fd(第一個引數)的檔案(和fd共享一個檔案表,當然也共享檔案偏移量)

強調第幾個引數是因為如果你寫成fd2=dup2(fd1,fd);那麼fd2 =fd,和fd1共享同一個檔案表。

   

#inclue<stdio.h>

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

#include<stdlib.h>

int main()

{

int fd = open("file",O_RDWR|O_CREAT,0644);

if(fd < 0)

printf("open error");

printf("fd:%d\n",fd);

//輸出fd=3;

int fd1 =open("text",,O_RDWR|O_CREAT,0644);

if(fd1 < 0)

printf("open error");

printf("fd1:%d\n",fd1);

//輸出fd1=4;

int fd2 = dup2(fd,fd1);

printf("fd2:%d\n",fd2);

//輸出fd2=4;

//fd1 =fd2=4;說明fd2使用了fd1的檔案描述符。

   

char buf[12]="hello,world";

write(fd,buf,12); //我們對fd進行了寫,並沒有對fd2進行寫

read(fd2,buf,12);//但是我們對fd2讀的時候,如果沒有寫,怎麼可能讀出來呢

printf("fd2:%s\n",buf);//事實是讀出來了

//輸出fd2:hello,world    //說明fd和fd2共用一個檔案表。

   

lseek(fd,5,SEEK_SET);//距離開始偏移5位,說明下次讀的時候是從第6個開始,注意我們是對fd進行偏移,沒有對fd2偏移

read(fd2,buf,5);  //但是如果讀fd2結果是從第6個字元開始的

buf[5]=0; //如果不寫這句,輸出的buf是按照12個字元輸出的。因為定義buf的時候陣列中可以放12個字元。

printf("fd2:%s\n",buf);//輸出fd2:,worl  //說明fd2和fd共享檔案偏移量。

close(fd);

close(fd2);

return 0;

}

dup和dup2的區別

dup:fd1= dup(fd);目標描述符使用了fd的檔案表

dup2:fd2 = dup2(fd1,fd)目標描述符使用了fd1的描述符,使用了fd的檔案表

 

 

linux程式設計之pipe()函式

管道是一種把兩個程序之間的標準輸入和標準輸出連線起來的機制,從而提供一種讓多個程序間通訊的方法,當程序建立管道時,每次都需要提供兩個檔案描述符來操作管道。其中一個對管道進行寫操作,另一個對管道進行讀操作。對管道的讀寫與一般的IO系統函式一致,使用write()函式寫入資料,使用read()讀出資料。

#include<unistd.h>

int pipe(int filedes[2])

返回值:成功,返回0,否則返回-1。引數陣列包含pipe使用的兩個檔案的描述符。fd[0]:讀管道,fd[1]寫管道。

必須在fork()中呼叫pipe(),否則子程序不會繼承檔案描述符。兩個程序不共享祖先程序,就不能使用pipe。但是可以使用命名管道。

1 #include<stdio.h>

2 #include<stdlib.h>

3 #include<string.h>

4 #include<unistd.h>

5 #include<sys/types.h>

6 int main(void){

7 int result=-1;

8 int fd[2],nbytes;

9 pid_t pid;

10 char string[]="hell world, my pipe!";

11 char readbuffer[100];

12 int *write_fd=&fd[1];

13 int *read_fd=&fd[0];

14 result=pipe(fd);;

15 if(-1==result){

16 printf("fail to create pipe\n");

17 return -1;

18 }

19 pid=fork();

20 if(-1==pid){

21 printf("fail to fork\n");

22 return -1;

23 }

24 if(0==pid){

25 close(*read_fd);

26 result=write(*write_fd,string,strlen(string));

27 return 0;

28 }else{

29 close(*write_fd);

30 nbytes=read(*read_fd,readbuffer,sizeof(readbuffer));

31 printf("the parent receive %d bytes data: %s \n",nbytes,readbuffer);

32 }

33 return 0;

34 }

 

the parent receive 20 bytes data: hell world, my pipe!

 

 

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

 

 

#define COUNT (10)

int main(int argc, char *argv[])  

{  

  int pipefd[2];  

  int read_count = 0;

  char buf[COUNT] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};;  

  if (pipe(pipefd) == -1) {  

    perror("call pipe failed \n");  

    exit(EXIT_FAILURE);  

  }  

  printf("write %d chars to pipe1 \n", COUNT);

  write(pipefd[1], buf, COUNT);  

 

 

  while (read(pipefd[0], &buf, 1) > 0) 

  {

    printf("read %c from pipe0\n", buf[0]);

    read_count++;

    if(read_count == COUNT)

    {

      printf("total read %d chars \n", read_count);

      break;

    }  

  } 

 

 

  close(pipefd[0]);  

  close(pipefd[1]);  

}  

 

編譯及執行結果:

[[email protected] core_dump]# gcc pipe.c 
[[email protected] core_dump]# ./a.out 
write 10 chars to pipe1 
read 0 from pipe0
read 1 from pipe0
read 2 from pipe0
read 3 from pipe0
read 4 from pipe0
read 5 from pipe0
read 6 from pipe0
read 7 from pipe0
read 8 from pipe0
read 9 from pipe0
total read 10 chars 

 

從shell中執行一個程序,預設會有3個檔案描述符存在(0、1、2), 0與程序的標準輸入相關聯,1與程序的標準輸出相關聯,2與程序的標準錯誤輸出相關聯,一個程序當前有哪些開啟的檔案描述符可以通過/proc/程序ID/fd目錄檢視

 

C語言提供了幾個標準庫函式,可以將任意型別(整型、長整型、浮點型等)的數字轉換為字串。


1.int/float to string/array:

C語言提供了幾個標準庫函式,可以將任意型別(整型、長整型、浮點型等)的數字轉換為字串,下面列舉了各函式的方法及其說明。
● itoa():將整型值轉換為字串。
● ltoa():將長整型值轉換為字串。
● ultoa():將無符號長整型值轉換為字串。
● gcvt():將浮點型數轉換為字串,取四捨五入。
● ecvt():將雙精度浮點型值轉換為字串,轉換結果中不包含十進位制小數點。
● fcvt():指定位數為轉換精度,其餘同ecvt()。


除此外,還可以使用sprintf系列函式把數字轉換成字串,其比itoa()系列函式執行速度慢

2. string/array to int/float
C/C++語言提供了幾個標準庫函式,可以將字串轉換為任意型別(整型、長整型、浮點型等)。

● atof():將字串轉換為雙精度浮點型值。
● atoi():將字串轉換為整型值。
● atol():將字串轉換為長整型值。
● strtod():將字串轉換為雙精度浮點型值,並報告不能被轉換的所有剩餘數字。
● strtol():將字串轉換為長整值,並報告不能被轉換的所有剩餘數字。
● strtoul():將字串轉換為無符號長整型值,並報告不能被轉換的所有剩餘數字。

以下是用itoa()函式將整數轉換為字串的一個例子:
# include <stdio.h>
# include <stdlib.h>
void main (void)
{
int num = 100;
char str[25];
itoa(num, str, 10);
printf("The number 'num' is %d and the string 'str' is %s. \n" ,
num, str);
}

itoa()函式有3個引數:第一個引數是要轉換的數字,第二個引數是要寫入轉換結果的目標字串,第三個引數是轉移數字時所用 的基數。在上例中,轉換基數為10。10:十進位制;2:二進位制...

 

 

C語言pthread_create傳遞帶多個引數的函式& pthread_join

pthread_create是類Unix作業系統(Unix、Linux、Mac OS X等)的建立執行緒的函式,標頭檔案在pthread.h中。函式的宣告如下:

int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,

(void*)(*start_rtn)(void*),void *arg);

//返回值:若成功則返回0,否則返回錯誤編號

引數
第一個引數為指向執行緒識別符號的指標。
第二個引數用來設定執行緒屬性。
第三個引數是執行緒執行函式的起始地址。
最後一個引數是執行函式的引數。

從第三個函式可以看到,傳入的函式引數需要為void*型別。但是很多情況下需要執行緒處理的函式是多引數的。可以通過把引數封裝成結構體的方式來實現傳遞帶多個引數的函式。

struct fun_para

{

var para1;//引數1

var para2;//引數2

.......

}

將這個結構體指標,作為void *形參的實際引數傳遞

struct fun_para para;

pthread_create(&ntid, NULL, thr_fn,&para);

接著線上程的呼叫函式thr_fn中可以通過下面的方式使用通過para傳入的引數。

void *thr_fn(void *arg)

{

fun_para *para;

para = (fun_para *) arg;

para->para1;//引數1

para->para2;//引數2

......

//pthread_exit(0);

return ((void *)0);

}

Additional Mark: 程式碼中如果沒有pthread_join,主執行緒會很快結束從而使整個程序結束,從而使建立的執行緒沒有機會開始執行就結束了。加入pthread_join後,主執行緒會一直等待直到等待的執行緒結束自己才結束,使建立的執行緒有機會執行。
函式定義:

int pthread_join(pthread_t thread, void **retval);

  • 1

描述 : pthread_join()函式,以阻塞的方式等待thread指定的執行緒結束。當函式返回時,被等待執行緒的資源被收回。如果執行緒已經結束,那麼該函式會立即返回。並且thread指定的執行緒必須是joinable的。
引數: thread: 執行緒識別符號,即執行緒ID,標識唯一執行緒。retval: 使用者定義的指標,用來儲存被等待執行緒的返回值。
返回值 : 0代表成功。 失敗,返回的則是錯誤號。

tmp1 = pthread_join(tid, &retval);

if (tmp1 != 0)

{

printf("cannot join with thread1\n");

}

多執行緒下變數-原子操作 __sync_fetch_and_add等等

    當然我們知道,count++這種操作不是原子的。一個自加操作,本質是分成三步的:
     1 從快取取到暫存器
     2 在暫存器加1
     3 存入快取。
    由於時序的因素,多個執行緒操作同一個全域性變數,會出現問題。這也是併發程式設計的難點。在目前多核條件下,這種困境會越來越彰顯出來。
    最簡單的處理辦法就是加鎖保護,這也是我最初的解決方案。看下面的程式碼:
      pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;

      pthread_mutex_lock(&count_lock);
      global_int++;
      pthread_mutex_unlock(&count_lock);
    後來在網上查詢資料,找到了__sync_fetch_and_add系列的命令,發現這個系列命令講的最好的一篇文章,英文好的同學可以直接去看原文。Multithreaded simple data type access and atomic variables

     __sync_fetch_and_add系列一共有十二個函式,有加/減/與/或/異或/等函式的原子性操作函式,__sync_fetch_and_add,顧名思義,現fetch,然後自加,返回的是自加以前的值。以count = 4為例,呼叫__sync_fetch_and_add(&count,1),之後,返回值是4,然後,count變成了5.
    有__sync_fetch_and_add,自然也就有__sync_add_and_fetch,呵呵這個的意思就很清楚了,先自加,在返回。他們哥倆的關係與i++和++i的關係是一樣的。被譚浩強他老人家收過保護費的都會清楚了。
    有了這個寶貝函式,我們就有新的解決辦法了。對於多執行緒對全域性變數進行自加,我們就再也不用理執行緒鎖了。下面這行程式碼,和上面被pthread_mutex保護的那行程式碼作用是一樣的,而且也是執行緒安全的。

__sync_fetch_and_add( &global_int, 1 );
    下面是這群函式的全家福,大家看名字就知道是這些函式是幹啥的了。

在用gcc編譯的時候要加上選項 -march=i686
type __sync_fetch_and_add (type *ptr, type value);
type __sync_fetch_and_sub (type *ptr, type value);
type __sync_fetch_and_or (type *ptr, type value);
type __sync_fetch_and_and (type *ptr, type value);
type __sync_fetch_and_xor (type *ptr, type value);
type __sync_fetch_and_nand (type *ptr, type value);
type __sync_add_and_fetch (type *ptr, type value);
type __sync_sub_and_fetch (type *ptr, type value);
type __sync_or_and_fetch (type *ptr, type value);
type __sync_and_and_fetch (type *ptr, type value);
type __sync_xor_and_fetch (type *ptr, type value);
type __sync_nand_and_fetch (type *ptr, type value);