Soal Jawab |. Perbezaan antara Linux GNU C dan ANSI C
Di Linux, pengkompil C yang tersedia ialah Pengkompil GNU C, yang dibina di atas Lesen Pengaturcaraan Yayasan Perisian Percuma dan oleh itu boleh diedarkan secara bebas. GNU C membuat satu siri sambungan kepada Standard C untuk meningkatkan kefungsian Standard C.
1. Tatasusunan panjang sifar dan panjang berubah
GNU C membenarkan tatasusunan sifar panjang. Ciri ini sangat berguna apabila mentakrifkan struktur pengepala objek panjang berubah-ubah. Contohnya:
struct var_data { int len; char data[0]; };
di sini,char data[0]
表示通过var_data
结构体的实例的data[index]
成员来访问len
之后的第index
个地址。值得注意的是,它并没有为data[]
数组分配内存,因此sizeof(struct var_data) = sizeof(int)
.
Anggap bahawa struct var_data
的数据域保存在紧接着struct var_data
berada dalam kawasan ingatan, maka kod berikut boleh digunakan untuk melintasi data ini:
struct var_data s; ... for (i = 0; i printf("%02x", s.data[i]);
Dalam GNU C, anda juga boleh menggunakan 1 pembolehubah untuk menentukan tatasusunan, seperti "double x[n]" yang ditakrifkan dalam kod berikut:
int main (int argc, char *argv[]) { int i, n = argc; double x[n]; for (i = 0; i return 0; }
2.case范围
GNU C支持case x…y这样的语法,区间[x,y]中的数都会满足这个case的条件,请看下面的代码:
switch (ch) { case '0'... '9': c -= '0'; break; case 'a'... 'f': c -= 'a' - 10; break; case 'A'... 'F': c -= 'A' - 10; break; }
代码中的case’0’…’9’等价于标准C中的:
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
3.语句表达式
GNU C把包含在括号中的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地 方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等,例如:
#define min_t(type,x,y) \ ( { type _ _x =(x);type _ _y = (y); _ _xfloat fa, fb, minf; mini = min_t(int, ia, ib); minf = min_t(float, fa, fb);
因为重新定义了__xx和__y这两个局部变量,所以用上述方式定义的宏将不会有副作用。在标准C中,对应的如 下宏则会产生副作用:
#define min(x,y) ((x)
代码min(++ia,++ib)会展开为((++ia)
4.typeof关键字
typeof(x)语句可以获得x的类型,因此,可以借助typeof重新定义min这个宏:
#define min(x,y) ({ \ const typeof(x) _x = (x); \ const typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x
我们不需要像min_t(type,x,y)那个宏那样把type传入,因为通过typeof(x)、typeof(y)可以获得type。代 码行(void)(&_x==&_y)的作用是检查_x和_y的类型是否一致。
5.可变参数宏
标准C就支持可变参数函数,意味着函数的参数是不固定的,例如printf()函数的原型为:
int printf( const char *format [, argument]... );
而在GNU C中,宏也可以接受可变数目的参数,例如:
#define pr_debug(fmt,arg...) \ printk(fmt,##arg)
这里arg表示其余的参数,可以有零个或多个参数,这些参数以及参数之间的逗号构成arg的值,在宏扩展时替换 arg,如下列代码:
pr_debug("%s:%d",filename,line)
会被扩展为:
printk("%s:%d", filename, line)
使用“##”是为了处理arg不代表任何参数的情况,这时候,前面的逗号就变得多余了。使用“##”之后,GNU C预 处理器会丢弃前面的逗号,这样,下列代码:
pr_debug("success!\n")
会被正确地扩展为:
printk("success!\n")
而不是:
printk("success!\n",)
6.标号元素
标准C要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C中,通过指定索引或结构体成员名,允许 初始化值以任意顺序出现。
指定数组索引的方法是在初始化值前添加“[INDEX]=”,当然也可以用“[FIRST…LAST]=”的形式指定一个范围。例如,下面的代码定义了一个数组,并把其中的所有元素赋值为0:
unsigned char data[MAX] = { [0 ... MAX-1] = 0 };
下面的代码借助结构体成员名初始化结构体:
struct file_operations ext2_file_operations = { llseek: generic_file_llseek, read: generic_file_read, write: generic_file_write, ioctl: ext2_ioctl, mmap: generic_file_mmap, open: generic_file_open, release: ext2_release_file, fsync: ext2_sync_file, };
但是,Linux 2.6推荐类似的代码应该尽量采用标准C的方式:
struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, .read = generic_file_read, .write = generic_file_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .ioct = ext2_ioctl, .mmap = generic_file_mmap, .open = generic_file_open, .release = ext2_release_file, .fsync = ext2_sync_file, .readv = generic_file_readv, .writev = generic_file_writev, .sendfile = generic_file_sendfile, };
7.当前函数名
GNU C预定义了两个标识符保存当前函数的名字,__FUNCTION__保存函数在源码中的名字,__PRETTY_FUNCTION__保存带语言特色的名字。在C函数中,这两个名字是相同的。
void example() { printf("This is function:%s", __FUNCTION__); }
代码中的__FUNCTION__意味着字符串“example”。C99已经支持__func__宏,因此建议在Linux编程中不再使用__FUNCTION__,而转而使用__func__:
void example(void) { printf("This is function:%s", __func__); }
8.特殊属性声明
GNU C允许声明函数、变量和类型的特殊属性,以便手动优化代码和定制代码检查的方法。要指定一个声明的 属性,只需要在声明后添加__attribute__((ATTRIBUTE))。其中ATTRIBUTE为属性说明,如果存在多个属 性,则以逗号分隔。GNU C支持noreturn、format、section、aligned、packed等十多个属性。
noreturn属性作用于函数,表示该函数从不返回。这会让编译器优化代码,并消除不必要的警告信息。例如:
# define ATTRIB_NORET __attribute__((noreturn)) .... asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;
format属性也用于函数,表示该函数使用printf、scanf或strftime风格的参数,指定format属性可以让编译器根据格 式串检查参数类型。例如:
asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2)));
上述代码中的第1个参数是格式串,从第2个参数开始都会根据printf()函数的格式串规则检查参数。
unused属性作用于函数和变量,表示该函数或变量可能不会用到,这个属性可以避免编译器产生警告信息。
aligned属性用于变量、结构体或联合体,指定变量、结构体或联合体的对齐方式,以字节为单位,例如:
struct example_struct { char a; int b; long c; } __attribute__((aligned(4)));
表示该结构类型的变量以4字节对齐。
packed属性作用于变量和类型,用于变量或结构体成员时表示使用最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小的内存。例如:
struct example_struct { char a; int b; long c __attribute__((packed)); };
编译器对结构体成员及变量对齐的目的是为了更快地访问结构体成员及变量占据的内存。例如,对 于一个32位的整型变量,若以4字节方式存放(即低两位地址为00),则CPU在一个总线周期内就可以读取32 位;否则,CPU需要两个总线周期才能读取32位。
9.内建函数
GNU C提供了大量内建函数,其中大部分是标准C库函数的GNU C编译器内建版本,例如memcpy()等,它们与对应的标准C库函数功能相同。
不属于库函数的其他内建函数的命名通常以__builtin开始,如下所示。
内建函数__builtin_return_address(LEVEL)返回当前函数或其调用者的返回地址,参数LEVEL指定调用栈的级数,如0表示当前函数的返回地址,1表示当前函数的调用者的返回地址。
内建函数__builtin_constant_p(EXP)用于判断一个值是否为编译时常数,如果参数EXP的值是常数,函数返回1,否则返回0。例如,下面的代码可检测第1个参数是否为编译时常数以确定采用参数版本还是非参数版本:
#define test_bit(nr,addr) \ (__builtin_constant_p(nr) \ constant_test_bit((nr),(addr)) : \ variable_test_bit((nr),(addr)))
内建函数__builtin_expect(EXP,C)用于为编译器提供分支预测信息,其返回值是整数表达式EXP的值,C的 值必须是编译时常数。
Linux内核编程时常用的likely()和unlikely()底层调用的likely_notrace()、unlikely_notrace()就是基于 __builtin_expect(EXP,C)实现的。
#define likely_notrace(x) __builtin_expect(!!(x), 1) #define unlikely_notrace(x) __builtin_expect(!!(x), 0)
若代码中出现分支,则即可能中断流水线,我们可以通过likely()和unlikely()暗示分支容易成立还是不容易 成立,例如:
if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) if (ipv4_is_loopback(saddr)) goto e_inval;
在使用gcc编译C程序的时候,如果使用“-ansi–pedantic”编译选项,则会告诉编译器不使用GNU扩展语法。例如对 于如下C程序test.c:
struct var_data { int len; char data[0]; }; struct var_data a;
直接编译可以通过:
gcc -c test.c
如果使用“-ansi–pedantic”编译选项,编译会报警:
gcc -ansi -pedantic -c test.c test.c:3: warning: ISO C forbids zero-size array 'data'
Atas ialah kandungan terperinci Soal Jawab |. Perbezaan antara Linux GNU C dan ANSI C. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Perbezaan utama antara CentOS dan Ubuntu adalah: asal (CentOS berasal dari Red Hat, untuk perusahaan; Ubuntu berasal dari Debian, untuk individu), pengurusan pakej (CentOS menggunakan yum, yang memberi tumpuan kepada kestabilan; Ubuntu menggunakan APT, untuk kekerapan yang tinggi) Pelbagai tutorial dan dokumen), kegunaan (CentOS berat sebelah ke arah pelayan, Ubuntu sesuai untuk pelayan dan desktop), perbezaan lain termasuk kesederhanaan pemasangan (CentOS adalah nipis)

Bagaimana cara menggunakan desktop Docker? Docktop Docktop adalah alat untuk menjalankan bekas Docker pada mesin tempatan. Langkah -langkah untuk digunakan termasuk: 1. Pasang desktop Docker; 2. Mulakan desktop Docker; 3. Buat imej Docker (menggunakan Dockerfile); 4. Membina imej Docker (menggunakan Docker Build); 5. Jalankan bekas Docker (menggunakan Docker Run).

CentOS telah dihentikan, alternatif termasuk: 1. Rocky Linux (keserasian terbaik); 2. Almalinux (serasi dengan CentOS); 3. Ubuntu Server (Konfigurasi diperlukan); 4. Red Hat Enterprise Linux (versi komersial, lesen berbayar); 5. Oracle Linux (serasi dengan CentOS dan RHEL). Apabila berhijrah, pertimbangan adalah: keserasian, ketersediaan, sokongan, kos, dan sokongan komuniti.

Langkah Pemasangan CentOS: Muat turun Imej ISO dan Burn Bootable Media; boot dan pilih sumber pemasangan; Pilih susun atur bahasa dan papan kekunci; Konfigurasikan rangkaian; memisahkan cakera keras; Tetapkan jam sistem; Buat pengguna root; pilih pakej perisian; Mulakan pemasangan; Mulakan semula dan boot dari cakera keras selepas pemasangan selesai.

Kaedah Melihat Proses Docker: 1. Docker CLI Command: Docker PS; 2. Systemd CLI Command: Sistem Status SistemCTL; 3. Docker mengarang arahan CLI: Docker-Compose PS; 4 Proses Explorer (Windows); 5. /Direktori Proc (Linux).

Docker menggunakan ciri -ciri kernel Linux untuk menyediakan persekitaran berjalan yang cekap dan terpencil. Prinsip kerjanya adalah seperti berikut: 1. Cermin digunakan sebagai templat baca sahaja, yang mengandungi semua yang anda perlukan untuk menjalankan aplikasi; 2. Sistem Fail Kesatuan (Unionfs) menyusun pelbagai sistem fail, hanya menyimpan perbezaan, menjimatkan ruang dan mempercepatkan; 3. Daemon menguruskan cermin dan bekas, dan pelanggan menggunakannya untuk interaksi; 4. Ruang nama dan cgroups melaksanakan pengasingan kontena dan batasan sumber; 5. Pelbagai mod rangkaian menyokong interkoneksi kontena. Hanya dengan memahami konsep -konsep teras ini, anda boleh menggunakan Docker dengan lebih baik.

Keperluan Sistem Kod Vs: Sistem Operasi: Windows 10 dan ke atas, MACOS 10.12 dan ke atas, pemproses pengedaran Linux: minimum 1.6 GHz, disyorkan 2.0 GHz dan ke atas memori: minimum 512 MB, disyorkan 4 GB dan ke atas ruang penyimpanan: minimum 250 mb, disyorkan 1 GB dan di atas keperluan lain:

Langkah Penyelesaian Masalah untuk Gagal Docker Image Build: Semak Sintaks Dockerfile dan Versi Ketergantungan. Semak jika konteks binaan mengandungi kod sumber dan kebergantungan yang diperlukan. Lihat log binaan untuk butiran ralat. Gunakan pilihan sasaran untuk membina fasa hierarki untuk mengenal pasti titik kegagalan. Pastikan anda menggunakan versi terkini Enjin Docker. Bina imej dengan --t [nama imej]: mod debug untuk debug masalah. Semak ruang cakera dan pastikan ia mencukupi. Lumpuhkan Selinux untuk mengelakkan gangguan dengan proses binaan. Tanya platform komuniti untuk mendapatkan bantuan, sediakan dockerfiles dan bina deskripsi log untuk cadangan yang lebih spesifik.
