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]);  

}  

 

編譯及執行結果:

[root@alexs-centos core_dump]# gcc pipe.c 
[root@alexs-centos 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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM