❶ 1.linux系統調用和庫函數調用的區別
系統調用:是操作系統為用戶態運行的進程和硬體設備(如CPU、磁碟、列印機等)進行交互提供的一組介面,即就是設置在應用程序和硬體設備之間的一個介面層。可以說是操作系統留給用戶程序的一個介面。再來說一下,linux內核是單內核,結構緊湊,執行速度快,各個模塊之間是直接調用的關系。放眼望整個linux系統,從上到下依次是用戶進程->linux內核->硬體。其中系統調用介面是位於Linux內核中的,如果再稍微細分一下的話,整個linux系統從上到下可以是:用戶進程->系統調用介面->linux內核子系統->硬體,也就是說Linux內核包括了系統調用介面和內核子系統兩部分;或者從下到上可以是:物理硬體->OS內核->OS服務->應用程序,其中操作系統起到「承上啟下」的關鍵作用,向下管理物理硬體,向上為操作系服務和應用程序提供介面,這里的介面就是系統調用了。
一般地,操作系統為了考慮實現的難度和管理的方便,它只提供一少部分的系統調用,這些系統調用一般都是由C和匯編混合編寫實現的,其介面用C來定義,而具體的實現則是匯編,這樣的好處就是執行效率高,而且,極大的方便了上層調用。
庫函數:顧名思義是把函數放到庫里。是把一些常用到的函數編完放到一個文件里,供別人用。別人用的時候把它所在的文件名用#include<>加到裡面就可以了。一般是放到lib文件里的。一般是指編譯器提供的可在c源程序中調用的函數。可分為兩類,一類是c語言標准規定的庫函數,一類是編譯器特定的庫函數。(由於版權原因,庫函數的源代碼一般是不可見的,但在頭文件中你可以看到它對外的介面)
libc中就是一個C標准庫,裡面存放一些基本函數,這些基本函數都是被標准化了的,而且這些函數通常都是用匯編直接實現的。
庫函數一般可以概括的分為兩類,一類是隨著操作系統提供的,另一類是由第三方提供的。隨著系統提供的這些庫函數把系統調用進行封裝或者組合,可以實現更多的功能,這樣的庫函數能夠實現一些對內核來說比較復雜的操作。比如,read()函數根據參數,直接就能讀文件,而背後隱藏的比如文件在硬碟的哪個磁軌,哪個扇區,載入到內存的哪個位置等等這些操作,程序員是不必關心的,這些操作裡面自然也包含了系統調用。而對於第三方的庫,它其實和系統庫一樣,只是它直接利用系統調用的可能性要小一些,而是利用系統提供的API介面來實現功能(API的介面是開放的)。部分Libc庫中的函數的功能的實現還是藉助了系統掉調用,比如printf的實現最終還是調用了write這樣的系統調用;而另一些則不會使用系統調用,比如strlen,
strcat,
memcpy等。
實時上,系統調用所提供給用戶的是直接而純粹的高級服務,如果想要更人性化,具有更符合特定情況的功能,那麼就要我們用戶自己來定義,因此就衍生了庫函數,它把部分系統調用包裝起來,一方面把系統調用抽象了,一方面方便了用戶級的調用。系統調用和庫函數在執行的效果上很相似(當然庫函數會更符合需求),但是系統調用是運行於內核狀態;而庫函數由用戶調用,運行於用戶態。
系統調用是為了方便使用操作系統的介面,而庫函數則是為了人們編程的方便。
❷ 在LINUX下,用C語言如何調用一個程序
在LINUX下,你可以使用VI編輯器。在CMDSHELL下執行。此外還需要用在linux平台下的編程軟體做輔助工具。
❸ 在Linux系統中,如何運行一個C語言程序
1、打開kali linux的終端。創建一個文件並命名為test.c。在終端輸入:touch test.c。
❹ 簡單的C語言代碼,關於linux系統調用。
不知道你的內核版本具體是多少,但是顯然你的 syscall number 345不對,在我的某台主機上, 345 對應的是 __NR_sendmmsg 這個syscall。 你應該先去確認你自己的syscall對應的號到底是多少。我估計你用的345執行的時候,syscall返回的應該是錯誤 (-1), 由於 -1 也是非零,所以總是滿足列印偶數的條件。 具體你可以用
int ret = syscall(345, n);
然後再判斷 ret 是否為-1來查看。
❺ 如何在C語言編程中調用linux系統終端下的命令
system(執行shell 命令)
相關函數 fork,execve,waitpid,popen
表頭文件 #include<stdlib.h>
定義函數 int system(const char * string);
函數說明 system()會調用fork()產生子進程,由子進程來調用/bin/sh-c string來執行參數string字元串所代表的命令,此命令執行完後隨即返回原調用的進程。在調用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被忽略。
返回值 如果system()在調用/bin/sh時失敗則返回127,其他失敗原因返回-1。若參數string為空指針(NULL),則返回非零值。如果system()調用成功則最後會返回執行shell命令後的返回值,但是此返回值也有可能為system()調用/bin/sh失敗所返回的127,因此最好能再檢查errno 來確認執行成功。
附加說明 在編寫具有SUID/SGID許可權的程序時請勿使用system(),system()會繼承環境變數,通過環境變數可能會造成系統安全的問題。
範例 #include<stdlib.h>
main()
{
system(「ls -al /etc/passwd /etc/shadow」);
}
執行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
-r--------- 1 root root 572 Sep 2 15 :34 /etc/shadow
❻ linux下怎樣用c語言調用shell命令
C程序調用shell腳本共同擁有三種法子 :system()、popen()、exec系列數call_exec1.c ,
system() 不用你自己去產生進程。它已經封裝了,直接增加自己的命令
exec 須要你自己 fork 進程,然後exec 自己的命令
popen() 也能夠實現運行你的命令,比system 開銷小
方法一、system()的使用。我直接上代碼吧
int system(const char *command);
我在/home/book/shell新建一個test.sh文件例如以下:
<span style="font-size:18px;"><span style="font-size:18px;">#!bin/bash
echo $HOME
echo "the is test!"</span></span>
test.c文件例如以下:
<span style="font-size:18px;"><span style="font-size:18px;">#include<stdlib.h>
int main()
{
system("bash /home/book/shell/test.sh"); /* chmod +x test.sh ,路徑前面要加上bash */
return 0;
}</span></span>
運行例如以下命令來編譯:
<span style="font-size:18px;">gcc test.c -o test
</span>
測試命令:
<span style="font-size:18px;">./test</span>
結果例如以下:
<span style="font-size:18px;">/root
the is test!</span>
方法二:popen() 會調用fork()產生 子歷程,然後從子歷程中調用/bin/sh -c來履行 參數command的指令。參數type可應用 「r」代表讀取。「w」代表寫入。遵循此type值。popen()會建立 管道連到子歷程的標准 輸出設備 或標准 輸入設備 ,然後返回一個文件指針。
隨後歷程便可利用 此文件指針來讀取子歷程的輸出設備 或是寫入到子歷程的標准 輸入設備 中。此外,全部應用 文 件指針(FILE*)操作的函數也都能夠應用 ,除了fclose()以外。
返回值:若成功 則返迴文件指針,否則返回NULL,差錯 原因存於errno中。注意:在編寫具SUID/SGID許可權的程序時請盡量避免應用 popen()。popen()會繼承環境變數。通過環境變數可能會造成系統安全的問題
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
其它不用改變我們直接改動test.c文件:
#include<stdio.h>
int main()
{
char buffer[80];
FILE *fp=popen("bash /home/book/shell/test.sh","r");
fgets(buffer,sizeof(buffer),fp);
printf("%s",buffer);
pclose(fp);
return 0;
}
方法三:exec函數簇 (我不太懂,別人的。也沒有驗證。習慣方法一)
須要注意的是exec並非1個函數, 事實上它僅僅是一組函數的統稱, 它包含以下6個函數:
#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[];
能夠見到這6個函數名字不同, 並且他們用於接受的參數也不同.
實際上他們的功能都是幾乎相同的, 由於要用於接受不同的參數所以要用不同的名字區分它們, 畢竟c語言沒有函數重載的功能嘛..
可是實際上它們的命名是有規律的:
exec[l or v][p][e]
exec函數里的參數能夠分成3個部分, 運行文件部分, 命令參數部分, 環境變數部分.
比如我要運行1個命令 ls -l /home/gateman
運行文件部分就是 "/usr/bin/ls"
命令參賽部分就是 "ls","-l","/home/gateman",NULL 見到是以ls開頭 每1個空格都必須分開成2個部分, 並且以NULL結尾的啊.
環境變數部分, 這是1個數組,最後的元素必須是NULL 比如 char * env[] = {"PATH=/home/gateman", "USER=lei", "STATUS=testing", NULL};
好了說下命名規則:
e興許, 參數必須帶環境變數部分, 環境變零部分參數會成為運行exec函數期間的環境變數, 比較少用
l 興許, 命令參數部分必須以"," 相隔, 最後1個命令參數必須是NULL
v 興許, 命令參數部分必須是1個以NULL結尾的字元串指針數組的頭部指針. 比如char * pstr就是1個字元串的指針, char * pstr[] 就是數組了, 分別指向各個字元串.
關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html
p興許, 運行文件部分能夠不帶路徑, exec函數會在$PATH中找
還有1個注意的是, exec函數會代替運行它的進程, 也就是說, 一旦exec函數運行成功, 它就不會返回了, 進程結束. 可是假設exec函數運行失敗, 它會返回失敗的信息, 並且進程繼續運行後面的代碼!
通常exec會放在fork() 函數的子進程部分, 來替代子進程運行啦, 運行成功後子程序就會消失, 可是運行失敗的話, 必須用exit()函數來讓子進程退出!
❼ 用C語言編寫程序完成以下的Unix/Linux系統的系統調用
//這個是我學Unix C++時對知識點總結程序,應該對你有些用吧。
/*
istream ostream
| \ / |
ifstream iostream ofstream
|
fstream
*/
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char ch[6];
cout << "Input a line: ";
ch[5] = cin.peek();
cout << "Peek first char: " << ch[5] << endl;
cin.get(ch[4]);
cout << "Read first char: " << ch[4] << endl;
cin.putback(ch[4]);
cin.getline(ch, 5);
if(!cin)
{
cout << "Input error!!!" << endl;
cin.clear();
cin.ignore(100, '\n');
}
else
cout << ch << endl;
cout << left << hex << showbase << uppercase << 1234 << endl;
cout << scientific << uppercase << left << 0.00123456 << endl;
cout.fill('*');
cout.width(8);
cout.unsetf(ios::dec | ios::oct);
cout.setf(ios::hex | ios::showbase | ios::uppercase | ios::left);
cout << 1234 << endl;
cout.setf(ios::dec);
ofstream fout("data.txt"); //使用fstream fio("data.txt", ios::in | ios::out);既可讀又可寫。
if(!fout.fail())
{
fout << "3.14159\t64I love C++" << endl;
fout.put('M');
fout.put('\n');
double d = 0.0123456789;
fout.precision(4);
fout.setf(ios::fixed);
// fout.setf(ios::scientific | ios::uppercase);
fout << d << endl;
fout.seekp(3, ios::cur); //讀使用seekg(),與seekp()類似。
fout << '*' << flush;
fout.seekp(3, ios::cur);
fout << endl;
fout.seekp(2, ios::cur);
fout << '@' << ' ' << '*' << ' ' << '@' << endl;
fout.seekp(2, ios::cur);
streampos j = fout.tellp();
while((fout.tellp()-j) < 5)
fout << '*' << flush;
cout << "文件寫入成功!" << endl;
}
else
cout << "文件打開失敗!" << endl;
fout.close();
ifstream fin;
fin.open("data.txt", ios::in); //類似可以如fout那樣定義
if(!fin.fail())
{
double d;
char ch[20] = {0};
string str;
fin >> d;
cout << d << endl;
fin.get(ch[0]);
for(int i=0; i<2; i++)
{
fin.get(ch[i]);
}
cout << ch << endl;
while(!fin.eof())
{
fin.getline(ch, 20, '\n');
cout << ch << endl;
}
}
else
cout << "文件打開失敗!" << endl;
fin.close();
ofstream fo;
fo.open("bin.bin", ios::binary|ios::app);
if(!fo.fail())
{
int a[10];
for(int i=0; i<10; i++)
a[i] = i;
fo.write((char *)a, sizeof(a));
}
else
cout << "文件打開失敗!" << endl;
fo.close();
ifstream fi;
fi.open("bin.bin", ios::binary|ios::in);
if(!fi.fail())
{
int a[10];
fi.read((char *)a, sizeof(a));
fi.close();
for(int i=0; i<10; i++)
cout << a[i];
cout << endl;
}
else
cout << "文件打開失敗!" << endl;
fi.close();
return 0;
}
❽ 紅帽linux中C語言編程如何調用數學函數
紅帽linux中C語言編程調用數學函數參考案例如下所示:
當需要調用函數的個數比較少時,可以直接在main函數中包含該文件,比如一個文件夾下包含add.c和main.c文件。
文件add.c定義兩個整數相加的函數,code如下:#include
❾ Linux下C語言程序中系統調用和庫函數調用可以共存
系統調用,一般有兩種,一種是API ,即application program interface即應用程序介面,我們所說的庫函數 實際上就是一種API函數,所以,這種情況下,它們是一種東西,所以可以共存,另外一種系統調用,是內核級的,在linux上可以直接通過內核調用指令,或者在C語言代碼中通過 asm關鍵字內聯調用。。這時候,這還是系統調用。。只不過是更低層的操作系統調用。。
❿ Linux下的c編程:系統調用
標準的c函數庫是所有的編譯都要具有的函數庫,(實際上還是略有不同),但是這些基本上實現方法略有不同,但是結果和標準是一樣的。但是linux的系統調用,調用是linux的系統庫,比如說unistd.h下的fork這個是Linux下特有,你在vs上,就沒有這個庫,也沒有這個函數。同樣在vs上寫c,你可以引入頭文件比如windows.h,顯然這個庫是Linux不具有的。簡單說系統調用庫根據具體的操作系統環境不同而不同,而c標准庫,是所有支持c語言編譯器都有的。