Rule 02. Declarations and Initialization

Rule 02. Declarations and Initialization

DCL30-C. Declare objects with appropriate storage durations

以合理的存储期(storage durations)声明对象。

这条规则的核心是要通过对象的存储期来明确其生命周期(lifetime),不能出现访问生命周期外对象的情况,尤其是在使用指针的时候。

一个错误示例如下,squirrel_away() 函数退出时,local 数组的生命周期结束,此时 ptr 访问了声明周期外的变量,是未定义的行为。

void squirrel_away(char **ptr_param) {
  char local[10];
  /* Initialize array */
  *ptr_param = local;
}
 
void rodent(void) {
  char *ptr;
  squirrel_away(&ptr);
  /* ptr is live but invalid here */
}

改进方式如下,local 具有静态(static)存储期,squirrel_away() 函数返回时,ptr 指向的内容仍是有效的。


char local[10];
  
void squirrel_away(char **ptr_param) {
  /* Initialize array */
  *ptr_param = local;
}
 
void rodent(void) {
  char *ptr;
  squirrel_away(&ptr);
  /* ptr is valid in this scope */
}

对象的存储期可分为:

  • static - 静态存储期
  • thread
  • automatic - 自动存储期
  • allocated

static 就是代码里用 static 修饰的对象,automatic 就是函数内不使用 static 声明的对象,allocated 就是用 malloc 相关函数分配的对象,而 thread 比较特殊,是用 __thread 修饰的对象,表明该对象是该线程专属的。


参考:

DCL31-C. Declare identifiers before using them

使用标识符前必须显式声明他们。

这条规则的核心是使用变量、函数时必须显式地声明他们。C90 标准允许变量和函数的隐式声明,但这在新的 C11 标准中被废弃了,并且新代码也不推荐使用隐式声明,以下有一些例子:

Noncompliant Code Example (Implicit int)

变量声明时如果缺乏类型定义,编译器会尝试隐式声明为 int 类型,例如下述的 foo

extern foo;

foo 可能是其他类型的变量,最终导致错误。

Noncompliant Code Example (Implicit Function Declaration)

当调用一个函数,而该函数并未声明,则 C90 标准会隐式声明一个标识符 extern int identifier();,其函数可以接收任意个数任意类型的参数,且返回值为 int 类型。例如下述例子:

#include <stddef.h>
/* #include <stdlib.h> is missing */
  
int main(void) {
  for (size_t i = 0; i < 100; ++i) {
    /* int malloc() assumed */
    char *ptr = (char *)malloc(0x10000000);
    *ptr = 'a';
  }
  return 0;
}

malloc() 函数的头文件 stdlib.h 并未 include,因此 C90 编译器隐式声明了 int malloc(),如果系统的 int 是 32bit,而指针是 64bit,这就会导致 malloc 返回的 64bit 数据被截断为 32bit,最终导致错误。

Noncompliant Code Example (Implicit Return Type)

当一个函数并未显式声明其返回值类型时,如果函数返回一个整数,C90 编译器隐式声明其返回值为 int 类型。下述例子中 foo() 函数的返回值类型被隐式声明为 int 类型,其返回的 UINT_MAX 被错误的转换成了 -1 。

#include <limits.h>
#include <stdio.h>
  
foo(void) {
  return UINT_MAX;
}
 
int main(void) {
  long long int c = foo();
  printf("%lld\n", c);
  return 0;
}

DCL36-C. Do not declare an identifier with conflicting linkage classifications

不要声明会导致链接冲突的标识符。

标识符的链接属性可分为三类:

  • 外部链接(External linkage):该标识符在整个程序中(所有编译单元和库)代表同一对象或函数。用 extern 声明的标识符具有文件作用域范围且未用 static 修饰的标识符都具有外部链接属性。
  • 内部链接(Internal linkage):该标识符在一个翻译单元(单个文件)内代表同一对象或函数。用 static 修饰的标识符具有内部链接属性。
  • 无链接(No linkage):可以在文件的其他地方声明名称相同的标识符。

多次声明具有不同连接属性的标识符,有时会有未定义的行为,应尽可能避免。

下图中显示了同时声明两个不同链接属性的标识符的最终结果,列为第一次声明,行为第二次声明。

一个简单例子如下,i2i5 都会产生未定义的行为。

int i1 = 10;         /* Definition, external linkage */
static int i2 = 20;  /* Definition, internal linkage */
extern int i3 = 30;  /* Definition, external linkage */
int i4;              /* Tentative definition, external linkage */
static int i5;       /* Tentative definition, internal linkage */
 
int i1;  /* Valid tentative definition */
int i2;  /* Undefined, linkage disagreement with previous */
int i3;  /* Valid tentative definition */
int i4;  /* Valid tentative definition */
int i5;  /* Undefined, linkage disagreement with previous */
 
int main(void) {
  /* ... */
  return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • 闲来翻译了一篇官方的JNI Tips,网上看到的翻译版本要么是时间久了不同步了,要么翻译的过于生硬,看得我怀疑自己...
    生活简单些阅读 1,715评论 1 4
  • 线程局部存储(Thread Local Storage,TLS)主要用于在多线程中,存储和维护一些线程相关的数据,...
    waruqi阅读 3,532评论 0 52
  • 参考链接今天看 MJRefresh 源码有一段忽略获的代码,借机整理下相关内容 #pragma在本质上是声明,常用...
    wpf_register阅读 6,749评论 0 2
  • 翻译自:http://llvm.org/docs/LangRef.html#######重启翻译 摘要 这篇文档是...
    呆萌院长阅读 9,384评论 5 4
  • 在iOS开发过程中, 我们可能会碰到一些系统方法弃用, weak、循环引用、不能执行之类的警告。 有代码洁癖的孩子...
    梦翔_d674阅读 2,260评论 0 3