打印

转:extern 与 static 关键字的完整说明

[复制链接]
3726|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tedyu|  楼主 | 2009-5-13 16:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
先分清C和C++再解释,有不同之处

1. C语言:

1.1. 首先要明确三个概念:
声明vs定义 —— 声明只规定对象的“类型”,定义则规定了对象的“实体”。一个对象,声明可以无穷多次,定义只能一次!
作用域 —— 指对象的“存取权限”
存储方式 —— 指变量为“静态数据段DS”或“堆栈段”变量

1.2. 对变量(变量有“存储方式”的问题):
extern:声明/定义变量,作用域=全局,存储方式=DS
static:定义变量,作用域=局部,存储方式=DS

extern声明的同时给变量赋了初值,那就同时做了定义,否则就只是声明
所以
extern int var = 0;
之类的东西是不应该出现在.h文件里的,而且在一个程序里只能出现一次,否则就是重复定义了

static变量如果出现在函数内,作用域只在函数内,否则就是当前文件。

函数内用static局部变量的意图不在于作用域,而在于将存储方式强制规定为静态,使“再入”时仍保持上一次的值。同一函数的所有“副本”都公用一个该变量的实体,因此使用了static变量的函数一般是“不可再入”的,不是“多线程安全”的。

1.3. 对函数(函数无所谓“存储方式”):
extern:声明/定义函数,作用域=全局
static:声明/定义函数,作用域=局部
extern/static如果只跟函数原型,就是声明,如果跟了函数体,就是定义。(有人不知道static也可以只声明不定义)
如果声明时指定了extern或static的,定义时可以省略extern/static,如果不省略,必须一致。

2. C++语言:
C++是C的超集,所以包含了上述特性,只是多了在类中使用static,和extern "C"的用法
类中使用static将成员声明为“静态”,类static成员的作用域是全局的,而非局部的(当然受privite/protected限制),且该类所有实体公用一个static成员实体,意图在于存储方式,不在作用域。
与其它成员不同,static成员需要单独的实体定义。
与C语言不同,类static成员在定义时,不能再用static修饰。

extern "C" 则是为了C++与C混合编程而设的


C/C++语言的extern/static/auto等关键字将声明/定义/作用域/存储方式等职能混在一起,为了减少关键字数量而没有分工,不规则,规定复杂,实在是给初学者出难题,我个人觉得设计得不好(但也许是能做到的当中最好的了),我见过编了十几年C程序的人还是有不会用的时候。

相关帖子

沙发
high| | 2009-5-14 01:18 | 只看该作者

这几个

玩10年的弄不明白要打pp的。 auto没有见过可以理解,其他的不知道就打pp。(不需要模块化编程的单片机除外)

要是补充个volatile, #pragma pack, __packed, __align...这些的说明就完美了。

使用特权

评论回复
板凳
high| | 2009-5-14 01:56 | 只看该作者

我知#pragma pack(n)是标准c

关于数据对齐

所有的内存数据访问可以分为以下类别:

    *

      自然对齐,例如,在位于 0x1000 的字边界上。 ARM 编译器通常对齐变量并填充结构,使得可以使用 LDR 和 STR 指令有效访问这些项。
    *

      已知但并非自然对齐,例如,位于地址 0x1001 的字。 此类对齐通常出现在压缩结构以删除不必要的填充时。在 C 和 C++ 中,__packed 限定符或 #pragma pack(n) 编译指令用于表示结构已压缩。
    *

      未知对齐,例如,位于任意地址的字。 此对齐类型通常出现在定义可以指向位于任何地址的字的指针时。在 C 和 C++ 中,__packed 限定符或 #pragma pack(n) 编译指令用于表示指针可以访问位于非自然对齐边界的字

使用特权

评论回复
地板
high| | 2009-5-14 02:15 | 只看该作者

armv6以上的版本就支持非对齐访问了。

举个例子看看我理解对吗

typedef unsigned int DWORD;

ReadDevice((char*)0x10000001);

int ReadDevice(char * pbuf)
{
    // 形参是char *pbuf, 会不会出现指向一个非4字节对齐的地址?
    // 可能性存在,虽然不是很大。

    DWORD deviceBuf[1024]; // 赶巧,因为设备接口,或者使用了DMA,就是4字节的缓冲。

    
    __packed DWORD * p = (DWORD*)pbuf; // 带了__packed关键字的就可以访问非对齐地址了。
    
   
    if ((unsigned) pbuf & 0x3) { // 不对齐了。
        *p = deviceBuf[0];
    } else *pbuf = deviceBuf[0];
    
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

52

帖子

0

粉丝