Maison > Tutoriel système > Linux > le corps du texte

Quelle est la différence entre Linux GNU C et ANSI C ?

王林
Libérer: 2024-02-05 16:30:13
avant
1409 Les gens l'ont consulté

Le compilateur C disponible sous Linux est le compilateur GNU C, qui est construit sur la licence de programmation de la Free Software Foundation et peut donc être librement distribué et utilisé. GNU C réalise une série d'extensions au standard C pour améliorer les fonctionnalités du standard C.

Linux GNU C 与 ANSI C 有什么区别?

1. Tableaux de longueur nulle et variable

GNU C permet l'utilisation de tableaux de longueur nulle, ce qui est très utile lors de la définition de la structure d'en-tête d'objets de longueur variable. Par exemple :

struct var_data { 
    int len; 
    char data[0]; 
};
Copier après la connexion

char data[0] signifie uniquement que le programme peut accéder à l'adresse d'index après len via le membre data[index] de l'instance de structure var_data. Il n'alloue pas de mémoire pour le tableau data[], donc sizeof (struct var_data) =. taille de (int).

En supposant que le champ de données de la struct var_data est stocké dans la zone mémoire immédiatement après la struct var_data, les données peuvent être parcourues via le code suivant :

struct var_data s; 
... 
for (i = 0; i printf("%02x", s.data[i]);
Copier après la connexion

Dans GNU C, vous pouvez également utiliser 1 variable pour définir un tableau, tel que "double x[n]" défini dans le code suivant :

int main (int argc, char *argv[]) 
{ 
    int i, n = argc; 
    double x[n]; 
    for (i = 0; i return 0; 
}
Copier après la connexion

2.portée du cas

GNU C prend en charge la syntaxe du cas x...y. Les nombres dans l'intervalle [x, y] rempliront les conditions de ce cas. Veuillez consulter le code suivant :

switch (ch) { 
case '0'... '9': c -= '0'; 
    break;
case 'a'... 'f': c -= 'a' - 10; 
    break; 
case 'A'... 'F': c -= 'A' - 10; 
    break; 
}
Copier après la connexion

la casse '0'...'9' dans le code est équivalente à celle du standard C :

case '0': case '1': case '2': case '3': case '4': 
case '5': case '6': case '7': case '8': case '9':
Copier après la connexion

3. Expression de la déclaration

GNU C traite l'instruction composée contenue entre parenthèses comme une expression, appelée expression d'instruction, qui peut apparaître partout où les expressions sont autorisées. Nous pouvons utiliser des boucles, des variables locales, etc. qui ne peuvent être utilisées que dans des instructions composées dans des expressions d'instruction, par exemple :

#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);
Copier après la connexion

Étant donné que les deux variables locales __xx et __y sont redéfinies, les macros définies de la manière ci-dessus n'auront aucun effet secondaire. En standard C, les macros correspondantes ci-dessous produiront des effets secondaires :

#define min(x,y) ((x) 
Copier après la connexion

Le code min(++ia,++ib) sera étendu à ((++ia)

4.type de mot-clé

L'instruction typeof(x) peut obtenir le type de x. Par conséquent, la macro min peut être redéfinie à l'aide de typeof :

.
#define min(x,y) ({ \ 
const typeof(x) _x = (x); \ 
const typeof(y) _y = (y); \ 
(void) (&_x == &_y); \ 
_x 
Copier après la connexion

Nous n'avons pas besoin de transmettre le type comme la macro min_t (type, x, y), car le type peut être obtenu via typeof (x), typeof (y). La fonction de la ligne de code (void) (&_x==&_y) est de vérifier si les types de _x et _y sont cohérents.

5. Macro à paramètres variables

Le standard C prend en charge les fonctions à paramètres variables, ce qui signifie que les paramètres de la fonction ne sont pas fixes. Par exemple, le prototype de la fonction printf() est :

.
int printf( const char *format [, argument]... );
Copier après la connexion

Dans GNU C, les macros peuvent également accepter un nombre variable de paramètres, par exemple :

#define pr_debug(fmt,arg...) \ 
printk(fmt,##arg)
Copier après la connexion

Ici, arg représente les paramètres restants, qui peuvent avoir zéro ou plusieurs paramètres. Ces paramètres et les virgules entre les paramètres constituent la valeur de arg arg est remplacé lors du développement de la macro, comme indiqué dans le code suivant :

.
pr_debug("%s:%d",filename,line)
Copier après la connexion

sera étendu à :

printk("%s:%d", filename, line)
Copier après la connexion

Utilisez "##" pour gérer la situation où arg ne représente aucun paramètre. À ce stade, la virgule précédente devient redondante. Après avoir utilisé "##", le préprocesseur GNU C supprimera la virgule précédente, donc le code suivant :

pr_debug("success!\n")
Copier après la connexion

sera correctement développé en :

printk("success!\n")
Copier après la connexion

au lieu de :

printk("success!\n",)
Copier après la connexion

6. Éléments d'étiquetage

La norme C exige que les valeurs d'initialisation d'un tableau ou d'une structure apparaissent dans un ordre fixe. Dans GNU C, les valeurs d'initialisation peuvent apparaître dans n'importe quel ordre en spécifiant des index ou des noms de membres de structure.

La façon de spécifier l'index du tableau est d'ajouter "[INDEX]=" avant la valeur d'initialisation. Bien sûr, vous pouvez également spécifier une plage sous la forme de "[FIRST...LAST]=". Par exemple, le code suivant définit un tableau et attribue à tous ses éléments la valeur 0 :

unsigned char data[MAX] = { [0 ... MAX-1] = 0 };
Copier après la connexion

Le code suivant initialise la structure à l'aide des noms des membres de la structure :

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, 
};
Copier après la connexion

Cependant, Linux 2.6 recommande que le code similaire soit autant que possible en standard 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, 
};
Copier après la connexion

7. Nom de la fonction actuelle

GNU C prédéfinit deux identifiants pour enregistrer le nom de la fonction actuelle, __FUNCTION__ enregistre le nom de la fonction dans le code source et __PRETTY_FUNCTION__ enregistre le nom avec les caractéristiques du langage. Dans la fonction C, ces deux noms sont identiques.

void example() 
{ 
    printf("This is function:%s", __FUNCTION__); 
}
Copier après la connexion

__FUNCTION__ dans le code signifie la chaîne "exemple". C99 prend déjà en charge la macro __func__, il est donc recommandé de ne plus utiliser __FUNCTION__ dans la programmation Linux et d'utiliser __func__ à la place :

void example(void) 
{ 
    printf("This is function:%s", __func__); 
}
Copier après la connexion

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;
Copier après la connexion

format属性也用于函数,表示该函数使用printf、scanf或strftime风格的参数,指定format属性可以让编译器根据格 式串检查参数类型。例如:

asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2)));
Copier après la connexion

上述代码中的第1个参数是格式串,从第2个参数开始都会根据printf()函数的格式串规则检查参数。

unused属性作用于函数和变量,表示该函数或变量可能不会用到,这个属性可以避免编译器产生警告信息。

aligned属性用于变量、结构体或联合体,指定变量、结构体或联合体的对齐方式,以字节为单位,例如:

struct example_struct { 
    char a; 
    int b; 
    long c; 
} __attribute__((aligned(4)));
Copier après la connexion

表示该结构类型的变量以4字节对齐。

packed属性作用于变量和类型,用于变量或结构体成员时表示使用最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小的内存。例如:

struct example_struct { 
    char a; 
    int b; 
    long c __attribute__((packed)); 
};
Copier après la connexion

编译器对结构体成员及变量对齐的目的是为了更快地访问结构体成员及变量占据的内存。例如,对 于一个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)))
Copier après la connexion

内建函数__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)
Copier après la connexion

若代码中出现分支,则即可能中断流水线,我们可以通过likely()和unlikely()暗示分支容易成立还是不容易 成立,例如:

if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev)))
    if (ipv4_is_loopback(saddr)) 
    goto e_inval;
Copier après la connexion

在使用gcc编译C程序的时候,如果使用“-ansi–pedantic”编译选项,则会告诉编译器不使用GNU扩展语法。例如对 于如下C程序test.c:

struct var_data { 
    int len; 
    char data[0]; 
};
struct var_data a;
Copier après la connexion

直接编译可以通过:

gcc -c test.c
Copier après la connexion

如果使用“-ansi–pedantic”编译选项,编译会报警:

gcc -ansi -pedantic -c test.c 
test.c:3: warning: ISO C forbids zero-size array 'data'
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:lxlinux.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal