GNU C 、ANSI C、标准C、标准c++区别和联系
GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统。它在编写linux的时候自己制作了一个标准成为 GNU C标准。ANSI 美国国家标准协会,它对C做的标准ANSI C标准后来被国际标准协会接收成为 标准C 所以 ANSI C 和标准C是一个概念
总体来说现在linux也支持标准C,以后标准C可以跨平台,而GUN c 一般只在linux c下应用
18.1 ANSI C和标准C++的差别
这里的ANSI C指的是最新的标准-C99
1、ANSI C不支持引用
2、ANSI C不支持函数重载
3、ANSI C多了两个整型(long long、unsigned long long),不过最新的C++编译器已经支持这两种整型
4、ANSI C不支持C++中的一个变量初始化方式,例如:int a(8);
5、ANSI C声明结构时必须使用struct关键字,而标准C++不需要
6、ANSI C标准库中的一些头文件,在标准C++中有了新的名称,例如ctime、cstring、climits、cfloat、cctype,有些文件不仅是名称上的变化
7、ANSI C不支持名称空间
8、ANSI C不包含bool类型,以及true和false关键字
9、声明函数时,参数为空的含义不同。在ANSI C中表示接受任意个数的参数,而在标准C++中表示不接受参数
10、ANSI C不支持内联函数
11、ASNI C不支持默认参数
12、ANSI C不支持可用于全局变量的作用域解析操作符(::)
13、使用const定义的全局常量在ANSI C中具有外部链接性,在标准C++中具有内部链接性,所以在标准C++中声明外部链接性的全局常量必须使用extern,例如:extern const int a = 10;
18.02GNU C比ANSI C扩展的地方
1.允许零长度数组
GNU C允许零长度数组,在定义变长对象的头结构时,这个特性非常有用。
struct var_data
{
int len;
char data[0];
};
char data[0]仅仅意味着程序中通过var_data的结构体实例的data[index]成员可以访问len之后的第index个地址,并没有为data[0]分配内存。
假设struct var_data的数据域保存在struct var_data紧接着的内存区域,通过如下代码可以遍历这些数据:
struct var_data s;
...
for (i=0;i
{
printf("%02x",s.data[i]);
}
2、case范围
GNU C 支持case x...y 这样的语法,区间[x,y]的数都会满足这个case的条件,记得数据结构试验时,有的同学为了做菜单使用了仅100个case,还好我做的是GUI的
switch(c)
{
case '0'...'9': c-='0';
break;
case 'a'...'f': c-='a'-10;
break;
case 'A'...'F': c-='A'-10;
break;
}
这个case的特点大家都看得出来,比标准C少敲了多少case啊
3、语句表达式
GNU C把包含在括号里的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环变量、局部变量等,例如
#define min_t(type,x,y) /
({type __x=(x); type __y=(y);__x<__y?__x:__y})
int ia,ib,mini;
mini=min_t(int,ia,ib);
这样,因为重新定义了__x和__y这两个局部变量,所以上述方法定义的宏将不会有副作用。在标准C中,对应的宏通常会有副作用:
#define min(x,y) ((x)<(y)?(x):(y))
而代码min(++ia,++ib)将会被展开为
((++ia)<(++ib)?(++ia):(++ib)) 传入宏的参数会被增加两次。
这个在 嵌入式程序员应知道的0x10个基本问题 里有讲过。
4、typeof关键字
typeof(x)语句可以获得x的类型,因此,我们可以借助typeof重新定义第3条提到的min_t这个宏
#define min(x,y) /
({ /
const typeof(x) _x=(x);/
const typeof(y) _y=(y);/
(void) (&_x==&_y);/
_x<_y ? _x: _y ; })
我们不需要像第三条时那样传一个type进去,因为通过typeof(x)可以得到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 DEMO_fops = {
owner : THIS_MODULE,
llseek: DEMO_llseek,
read: DEMO_read,
write: DEMO_write,
ioctl: DEMO_ioctl,
open: DEMO_open,
release: DEMO_release,
};
但是Linux 2.6还是推荐采用标准C的方式,如下
struct file_operations DEMO_fops = {
.owner = THIS_MODULE,
.llseek = DEMO_llseek,
.read = DEMO_read,
.write = DEMO_write,
.ioctl = DEMO_ioctl,
.open = DEMO_open,
.release = DEMO_release,
};
7.当前函数名
GUN C预定义了两个标识符保存当前的函数名,__FUNCTION__保存函数在源码中的名字,
__PRETTY_FUNCTION__保存带语言特色的名字。在c函数中,这两个名字是相同的。
void example()
{
printf("This is function: %s ",__FUNCTION__);
}
代码中的__FUNCTION__意味着字符串"example"
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)));
详细的可以看http://blog.163.com/sunm_lin/blog/static/9192142200741533038695/
unused属性作用于函数和变量,表示该函数或变量可能不会被用到,避免编译器产生的警告信息。
aligned属性指定结构体、变量、联合体的对齐方式。packed属性作用于变量和类型,表示压缩结构体,使用最小的内存。
struct examprl_struct
{
char a;
int b;
long c;
}__attribute__((packed));
注意,这个__attribute__((packed))只能用在GNU C
关于在VC下的结构体对齐,参照http://hi.baidu.com/deep_pro/blog/item/421db081aeb604debd3e1e01.html
9、内建函数
GNU C 提供了大量的内建函数,其中很多是标准 C 库函数的内建版本,例如memcpy,它们与对应的 C 库函数功能相同,本文不讨论这类函数,其他内建函数的名字通常以 __builtin 开始。
* __builtin_return_address (LEVEL)
内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址,依此类推。例如:
++++ kernel/sched.c
437: printk(KERN_ERR “schedule_timeout: wrong timeout ”
438: “value %lx from %p/n”, timeout,
439: __builtin_return_address(0));
* __builtin_constant_p(EXP)
内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数 EXP 的值是常数,函数返回 1,否则返回0。例如:
++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) /
250: (__builtin_constant_p(nr) ? /
251: constant_test_bit((nr),(addr)) : /
252: variable_test_bit((nr),(addr)))
很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。
* __builtin_expect(EXP, C)
内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表达式 EXP 的值,C 的值必须是编译时常数。例如:
++++ include/linux/compiler.h
13: #define likely(x) __builtin_expect((x),1)
14: #define unlikely(x) __builtin_expect((x),0)
++++ kernel/sched.c
564: if (unlikely(in_interrupt())) {
565: printk(”Scheduling in interrupt/n”);
566: BUG();
567: }
这个内建函数的语义是 EXP 的预期值是 C,编译器可以根据这个信息适当地重排语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中断上下文是很少发生的,第 565-566 行的目标码可能会放在较远的位置,以保证经常执行的目标码更紧凑
总结:GNU c运用于linux上,ANSI c就是标准c库函数,GNU包含ANSI,ANSI可以跨平台。ANSI和C++库有交集,也有不同
2015年05月09日 00:03:12 独自等待2016 阅读数:749
没有函数实现的源代码,win不开源
api的名称与posix定义的api的名称不一样,win按自己的标准
同样微软提供的库,方便开发win32程序
基于面向对象的特征,对win32 复杂api 进行封装
几近淘汰
2014年02月14日 15:15:35 optics_ts 阅读数:2827
Glibc
众所周知,C 语言并没有为常见的操作,例如输入/输出、内存管理,字符串操作等提供内置的支持。 相反,这些功能一般由标准的“函数库”来提供。GNU 的 C 函数库,即 glibc,是 Linux 上最重要的 函数库,它定义了 ISO C 标准指定的所有的库函数,以及由 POSIX 或其他 UNIX 操作系统 统变种指定的附加特色,还包括有与 GNU 系统相关的扩展。目前,流行的 Linux 系统使用 glibc 2.0 以上的版本。glibc 基于如下标准:
系统调用
系统调用是操作系统提供给外部程序的接口。在 C 语言中,操作系统的系统调用通常通过 函数调用的形式完成,这是因为这些函数封装了系统调用的细节,将系统调用的入口、参数以及 返回值用 C 语言的函数调用过程实现。在 Linux 系统中,系统调用函数定义在 glibc 中。
谈到系统调用时,需要注意如下几点:
有关系统调用我们将在以后详细讲述。
1. man
man,即 manunal,是 UNIX 系统手册的电子版本。根据习惯,UNIX 系统手册通常分为 不同的部分(或小节,即 section),每个小节阐述不同的系统内容。目前的小节划分如下:
其他手册小节:
手册页一般保存在 /usr/man 目录下,其中每个子目录(如 man1, man2, ..., manl, mann) 包含不同的手册小节。使用 man 命令查看手册页。
man 命令行:
man [-acdfFhkKtwW] [-m system] [-p string] [-C config_file] [-M path] [-P pager] [-S section_list] [section] name
常用命令行:
$ man open
$ man 7 man
$ man ./myman.3
2. info
Linux 中的大多数软件开发工具都是来自自由软件基金会的 GNU 项目,这些工具软件 件的在线文档都以 info 文件的形式存在。info 程序是 GNU 的超文本帮助系统。
info 文档一般保存在 /usr/info 目录下,使用 info 命令查看 info 文档。
要运行 info,可以在 shell 提示符后输入 info,也可以在 GNU 的 emacs 中键入 Esc-x 后跟 info。
info 帮助系统的初始屏幕显示了一个主题目录,你可以将光标移动到带有 * 的主题菜单上面,然后按回车键
进入该主题,也可以键入 m,后跟主题菜单的名称而进入该主题。例如,你可以键入 m,然后再键入 gcc 而进
进入 gcc 主题中。
如果你要在主题之间跳转,则必须记住如下的几个命令键:
* n:跳转到该节点的下一个节点;
* p:跳转到该节点的上一个节点;
* m: 指定菜单名而选择另外一个节点;
* f:进入交叉引用主题;
* l:进入该窗口中的最后一个节点;
* TAB:跳转到该窗口的下一个超文本链接;
* RET:进入光标处的超文本链接;
* u:转到上一级主题;
* d:回到 info 的初始节点目录;
* h:调出 info 教程;
* q:退出 info。
#DEMO#
3. HOW-TO
可供用户参考的联机文档的另一种形式是 HOWTO 文件,这些文件位于系统的 /usr/doc/HOWTO 目录下。 HOWTO 文件的文件名都有一个 -HOWTO 后缀,并且都是文本文件。
每一个 HOWTO 文件包含 Linux 某一方面的信息,例如它支持的硬件或如何建立一个引导盘。
要想查看这些文件,进入 /usr/doc/HOWTO 目录,使用 more 命令,具体形式如下:
$ cd /usr/doc/HOWTO; more topic-name-HOWTO
另外,HOWTO 文档还有其他格式的文件,例如 HTML 和 PS 等,保存在 /usr/doc/HOWTO/other-formats 下。
4. 其他
Linux 的内核文档一般包含在内核源代码中,目录如下:/usr/src/linux-2.x.x/Documentation
/usr/doc 目录下包含有大量与特定软件或函数库相关的说明性文档。
1. 函数库
2. 头文件
POSIX 现在已经发展成为一个非常庞大的标准族,某些部分正处在开发过程中。表 1-1 给出了 POSIX 标准的几个 重要组成部分。POSIX 与 IEEE 1003 和 2003 家族的标准是可互换的。除 1003.1 之外,1003 和 2003 家族也包括在表中。
1-1 POSIX 标准的重要组成部分
1003.0 |
管理 POSIX 开放式系统环境(OSE)。IEEE 在 1995 年通过了这项标准。 ISO 的版本是 ISO/IEC 14252:1996。 |
1003.1 |
被广泛接受、用于源代码级别的可移植性标准。1003.1 提供一个操作系统的 C 语言应 用编程接口(API)。IEEE 和 ISO 已经在 1990 年通过了这个标准,IEEE 在 1995 年 重新修订了该标准。 |
1003.1b |
一个用于实时编程的标准(以前的 P1003.4 或 POSIX.4)。这个标准在 1993 年 被 IEEE 通过,被合并进 ISO/IEC 9945-1。 |
1003.1c |
一个用于线程(在一个程序中当前被执行的代码段)的标准。以前是 P1993.4 或 POSIX.4 的一部分,这个标准已经在 1995 年被 IEEE 通过,归入 ISO/IEC 9945-1:1996。 |
1003.1g |
一个关于协议独立接口的标准,该接口可以使一个应用程序通过网络与另一个应用程序 通讯。 1996 年,IEEE 通过了这个标准。 |
1003.2 |
一个应用于 shell 和 工具软件的标准,它们分别是操作系统所必须提供的命令处理器 和工具程序。 1992 年 IEEE 通过了这个标准。ISO 也已经通过了这个标准(ISO/IEC 9945-2:1993)。 |
1003.2d |
改进的 1003.2 标准。 |
1003.5 |
一个相当于 1003.1 的 Ada 语言的 API。在 1992 年,IEEE 通过了这个标准。 并在 1997 年对其进行了修订。ISO 也通过了该标准。 |
1003.5b |
一个相当于 1003.1b(实时扩展)的 Ada 语言的 API。IEEE 和 ISO 都已经通过了 这个标准。ISO 的标准是 ISO/IEC 14519:1999。 |
1003.5c |
一个相当于 1003.1q(协议独立接口)的 Ada 语言的 API。在 1998 年, IEEE 通过了这个标准。ISO 也通过了这个标准。 |
1003.9 |
一个相当于 1003.1 的 FORTRAN 语言的 API。在 1992 年,IEEE 通过了这个标准, 并于 1997 年对其再次确认。ISO 也已经通过了这个标准。 |
1003.10 |
一个应用于超级计算应用环境框架(Application Environment Profile,AEP)的标准。 在 1995 年,IEEE 通过了这个标准。 |
1003.13 |
一个关于应用环境框架的标准,主要针对使用 POSIX 接口的实时应用程序。 在 1998 年,IEEE 通过了这个标准。 |
1003.22 |
一个针对 POSIX 的关于安全性框架的指南。 |
1003.23 |
一个针对用户组织的指南,主要是为了指导用户开发和使用支持操作需求的 开放式系统环境(OSE)框架 |
2003 |
针对指定和使用是否符合 POSIX 标准的测试方法,有关其定义、一般需求和指导方针的 一个标准。在 1997 年,IEEE 通过了这个标准。 |
2003.1 |
这个标准规定了针对 1003.1 的 POSIX 测试方法的提供商要提供的一些条件。 在 1992 年,IEEE 通过了这个标准。 |
2003.2 |
一个定义了被用来检查与 IEEE 1003.2(shell 和 工具 API)是否符合的测试方法的 标准。在 1996 年,IEEE 通过了这个标准。 |
除了 1003 和 2003 家族以外,还有几个其它的 IEEE 标准,例如 1224 和 1228,它们 也提供开发可移植应用程序的 API。要想得到关于 IEEE 标准的最新信息,可以访问 IEEE 标准的主页,网址是 http://standard.ieee.org/。 有关 POSIX 标准的概述信息,请访问 Web 站点http://standards.ieee.org/reading/ieee/stad_public/description/posix/。
C语言原来是没有统一的标准的,第一个标准是90左右确定的,内容较以前有些改进:
1、增加了真正的标准库;
2、新的预处理命令与特性;
3、函数原型允许在函数申明中;
4、指定参数类型一些新的关键字,包括 const、volatile 与 signed;
5、宽字符、宽字符串与多字节字符;
6、对约定规则、声明和类型检查的许多小改动与澄清;
后来到了99年就有了新的修正:
1、增加了对编译器的限制,比如源程序每行要求至少支持到 4095 字节,变量名函数名的要求支持到 63 字节(extern 要求支持到 31);
2、增强了预处理功能。例如:宏支持取可变参数 #define Macro(...) __VA_ARGS__;
使用宏的时候,允许省略参数,被省略的参数会被扩展成空串;
支持 // 开头的单行注释(这个特性实际上在C89的很多编译器上已经被支持了);
3、增加了新关键字 restrict, inline, _Complex, _Imaginary, _Bool;支持 long long, long double _Complex, float _Complex 等类型;
4、支持不定长的数组,即数组长度可以在运行时决定,比如利用变量作为数组长度。声明时使用 int a[var]的形式。不过考虑到效率和实现,不定长数组不能用在全局,或struct 与union 里。
5、变量声名不必放在语句块的开头,,for 语句提倡写成 for(int i=0;i<100;++i) 的形式,即i 只在for 语句块内部有效。
6、允许采用(type_name){xx,xx,xx} 类似于 C++ 的构造函数的形式构造匿名的结构体。
7、初始化结构的时候允许对特定的元素赋值,形式为:
struct test{int a[3],b;} foo[] = { [0].a = {1}, [1].a = 2 }
struct test{int a, b, c, d;} foo= { .a=1, .c=3,4, .b=5 }; // 3,4 是对 .c,.d 赋值的
8、格式化字符串中,利用 \u 支持 unicode 的字符。
9、支持 16 进制的浮点数的描述;printf scanf 的格式化串增加了对 long long int 类型的支持;浮点数的内部数据描述支持了新标准,可以使用 #pragma 编译器指令指定。
10、除了已有的 __line__ __file__ 以外,增加了 __func__ 得到当前的函数名。
11、允许编译器化简非常数的表达式;取消了函数返回类型默认为 int 的规定。
12、修改了 / % 处理负数时的定义,这样可以给出明确的结果,例如在C89中-22 / 7 = -3, -22 % 7 = -1,也可以-22 / 7= 4, -22 % 7 = 6。 而C99中明确为-22 / 7 = -3, -22 % 7 = -1,只有一种结果。
13、允许 struct 定义的最后一个数组不指定其长度,写做 [](flexible array member)。
14、const const int i 将被当作const int i 处理;输入输出对宽字符以及长整数等做了相应的支持。
15、增加和修改了一些标准头文件,比如定义 bool 的
在11年的时候ISO正式发布了新的C语言的新标准C11:
1、对齐处理(Alignment)的标准化(包括_Alignas标志符,alignof运算符, aligned_alloc函数以及
2、_Noreturn 函数标记,类似于 gcc 的 __attribute__((noreturn))。
3、_Generic 关键字。
4、多线程(Multithreading)支持,包括:
_Thread_local存储类型标识符,
_Atomic类型修饰符和
5、增强的Unicode的支持。基于C Unicode技术报告ISO/IEC TR 19769:2004,增强了对Unicode的支持。包括为UTF-16/UTF-32编码增加了char16_t和char32_t数据类型,提供了包含unicode字符串转换函数的头文件
6、删除了 gets() 函数,使用一个新的更安全的函数gets_s()替代。
7、增加了边界检查函数接口,定义了新的安全的函数,例如 fopen_s(),strcat_s()
8、匿名结构体/联合体支持。这个在gcc早已存在,C11将其引入标准。
9、静态断言(Static assertions),_Static_assert(),在解释 #if 和 #error 之后被处理。
10、新的 fopen() 模式,(“…x”)。类似 POSIX 中的 O_CREAT|O_EXCL,在文件锁中比较常用。
11、新增 quick_exit() 函数作为第三种终止程序的方式。当 exit()失败时可以做最少的清理工作。
C90和C99容易弄混,这也是现在用的最多的两个版本,至于C11的话基本没见人用,反正有了也总结一下 。