Linux GNU C와 ANSI C의 차이점은 무엇입니까?

王林
풀어 주다: 2024-02-05 16:30:13
앞으로
1408명이 탐색했습니다.

Linux에서 사용할 수 있는 C 컴파일러는 GNU C 컴파일러로, 자유 소프트웨어 재단의 프로그래밍 라이센스를 기반으로 구축되었으므로 자유롭게 배포하고 사용할 수 있습니다. GNU C는 표준 C의 기능을 향상시키기 위해 표준 C에 대한 일련의 확장을 만듭니다.

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

1. 길이가 0인 배열과 가변 길이 배열

GNU C에서는 길이가 0인 배열을 사용할 수 있는데, 이는 가변 길이 객체의 헤더 구조를 정의할 때 매우 유용합니다. 예:

으아아아

char data[0]는 프로그램이 var_data 구조 인스턴스의 data[index] 멤버를 통해 len 이후의 인덱스 주소에 액세스할 수 있다는 것을 의미합니다. data[] 배열에 메모리를 할당하지 않으므로 sizeof(struct var_data) = 크기(정수).

struct var_data의 데이터 필드가 struct var_data 바로 뒤의 메모리 영역에 저장되어 있다고 가정하면 다음 코드를 통해 데이터를 탐색할 수 있습니다.

으아아아

GNU C에서는 다음 코드에 정의된 "double x[n]"과 같이 변수 1개를 사용하여 배열을 정의할 수도 있습니다.

으아아아

2.케이스 범위

GNU C는 x...y 구문을 지원합니다. 간격 [x, y]의 숫자는 이 경우의 조건을 충족합니다.

으아아아

코드의 '0'...'9' 사례는 표준 C의 사례와 동일합니다:

으아아아

3. 진술 표현

GNU C는 괄호 안에 포함된 복합 명령문을 명령문 표현식이라고 하는 표현식으로 처리합니다. 이 표현식은 표현식이 허용되는 모든 곳에 나타날 수 있습니다. 명령문 표현식의 복합 명령문에만 사용할 수 있는 루프, 지역 변수 등을 사용할 수 있습니다. 예:

으아아아

두 개의 지역 변수 __xx와 __y가 재정의되기 때문에 위와 같은 방식으로 정의된 매크로는 부작용이 없습니다. 표준 C에서는 아래의 해당 매크로가 부작용을 발생시킵니다.

으아아아

코드 min(++ia,++ib)은 ((++ia)로 확장됩니다.

4.키워드 유형

typeof(x) 문은 x 유형을 얻을 수 있습니다. 따라서 min 매크로는 typeof를 사용하여 재정의할 수 있습니다.

으아아아

typeof(x) 및 typeof(y)를 통해 유형을 얻을 수 있으므로 min_t(type, x, y) 매크로와 같은 유형을 전달할 필요가 없습니다. 코드 라인(void)(&_x==&_y)의 기능은 _x와 _y의 유형이 일치하는지 확인하는 것입니다.

5. 가변 매개변수 매크로

표준 C는 가변 매개변수 함수를 지원합니다. 이는 함수의 매개변수가 고정되지 않음을 의미합니다. 예를 들어 printf() 함수의 프로토타입은 다음과 같습니다. 으아아아

GNU C에서 매크로는 가변 개수의 매개변수를 허용할 수도 있습니다. 예:

으아아아

여기서 arg는 0개 이상의 매개변수를 가질 수 있는 나머지 매개변수를 나타냅니다. 이러한 매개변수와 매개변수 사이의 쉼표는 다음 코드와 같이 매크로 확장 중에 대체됩니다. 으아아아

다음으로 확장됩니다.

으아아아

arg가 어떤 매개변수도 나타내지 않는 상황을 처리하려면 "##"을 사용하세요. 이때 앞의 쉼표는 중복됩니다. "##"을 사용한 후 GNU C 전처리기는 앞의 쉼표를 삭제하므로 다음 코드는 다음과 같습니다.

으아아아

는 다음과 같이 올바르게 확장됩니다.

으아아아

대신:

으아아아

6. 라벨 요소

표준 C에서는 배열이나 구조체의 초기화 값이 고정된 순서로 나타나야 합니다. GNU C에서는 인덱스나 구조체 멤버 이름을 지정하여 초기화 값이 어떤 순서로든 나타날 수 있습니다.

배열 인덱스를 지정하는 방법은 초기화 값 앞에 "[INDEX]="를 추가하는 것입니다. 물론 "[FIRST...LAST]=" 형식으로 범위를 지정할 수도 있습니다. 예를 들어, 다음 코드는 배열을 정의하고 그 안의 모든 요소를 ​​0에 할당합니다.

으아아아

다음 코드는 구조체 멤버 이름을 사용하여 구조체를 초기화합니다.

으아아아

그러나 Linux 2.6에서는 유사한 코드가 가능한 한 표준 C에 있어야 한다고 권장합니다.

으아아아

7. 현재 함수 이름

GNU C에서는 현재 함수의 이름을 저장하기 위해 두 개의 식별자를 미리 정의하고 있고, __FUNCTION__은 소스 코드에 함수의 이름을 저장하고, __PRETTY_FUNCTION__은 언어 특성을 지닌 이름을 저장합니다. C 함수에서 이 두 이름은 동일합니다.

으아아아 코드에서

__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'
로그인 후 복사

위 내용은 Linux GNU C와 ANSI C의 차이점은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:lxlinux.net
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿