GCC-3.4.6源代码学习笔记(25)

3.3.3.1.1.            C++的选项

对于CC++或者obj-Clang_hookshandle_options都是c_common_handle_option。下面的OPT_*用作cl_options数组的索引。

 

251  int

252  c_common_handle_option (size_t scode, const char *arg, int value)                in c-opts.c

253  {

254    const struct cl_option *option = &cl_options[scode];

255    enum opt_code code = (enum opt_code) scode;

256    int result = 1;

257 

258    switch (code)

259    {

260      default:

261        result = permit_fortran_options;

262        break;

263 

264      case OPT__output_pch_:

265        pch_file = arg;

266        break;

267 

268      case OPT_A:

269        defer_opt (code, arg);

270        break;

271 

272      case OPT_C:

273        cpp_opts->discard_comments = 0;

274        break;

275 

276      case OPT_CC:

277        cpp_opts->discard_comments = 0;

278        cpp_opts->discard_comments_in_macro_exp = 0;

279        break;

280 

281      case OPT_D:

282        defer_opt (code, arg);

283        break;

284 

285      case OPT_E:

286        flag_preprocess_only = 1;

287        break;

288 

289      case OPT_H:

290        cpp_opts->print_include_names = 1;

291        break;

292 

293      case OPT_I:

294        if (strcmp (arg, "-"))

295          add_path (xstrdup (arg), BRACKET, 0);

296        else

297        {

298          if (quote_chain_split)

299            error ("-I- specified twice");

300          quote_chain_split = true;

301          split_quote_chain ();

302        }

303        break;

304 

305      case OPT_M:

306      case OPT_MM:

307        /* When doing dependencies with -M or -MM, suppress normal

308          preprocessed output, but still do -dM etc. as software

309          depends on this. Preprocessed output does occur if -MD, -MMD

310          or environment var dependency generation is used.  */

311        cpp_opts->deps.style = (code == OPT_M ? DEPS_SYSTEM: DEPS_USER);

312        flag_no_output = 1;

313        cpp_opts->inhibit_warnings = 1;

314        break;

315 

316      case OPT_MD:

317      case OPT_MMD:

318        cpp_opts->deps.style = (code == OPT_MD ? DEPS_SYSTEM: DEPS_USER);

319        deps_file = arg;

320        break;

321 

322      case OPT_MF:

323        deps_seen = true;

324        deps_file = arg;

325        break;

 

265行,pch_file表示我们要作为预编译头文件的文件名,或者为NULL如果不需要产生预编译头文件。

268行,-Aquestion[=answer]指定了,对应于具有以下形式的断言的,回答(answer):

#if #question(answer)

也可以使用–assert代替–A,作为这个选项。

而在281行,-Dmacro[=string],如果string被指定,具有`macro`名字的宏被定义,就好像在代码中被定义那样。例如,-Dbrunt=logger将产生如下定义:

#define brunt=logger

如果string没有指定,string被认为是“1”。例如,-Dminke将产生如下定义:

#define minke 1

所有的-D选项都在任一一个-U选项前得到处理,而所有-U选项在任一一个-include或者-imacros选项前处理。

选项–A–D,现阶段都由defer_opt处理,注意到arg指向-A-D后的字符串。

 

179  static void

180  defer_opt (enum opt_code code, const char *arg)                                          in c-opts.c

181  {

182    deferred_opts[deferred_count].code = code;

183    deferred_opts[deferred_count].arg = arg;

184    deferred_count++;

185  }

 

deferred_opts保存由c_common_handle_option解析的选项,但它们的处理要推迟到函数c_common_post_options中。

如果flag_preprocess_only–E)成立,编译器在对源代码进行预处理后,就会停下并输出结果。这个结果会由标准输出输出,除非使用了-o选项指定了输出文件。那些不需要预处理的输入文件将被忽略。而是否需要处理则要么由文件名后缀,或者由-x选项指明语言类型,来确定。这个选项定义环境变量__GNUC____GNUC_MINOR____GNUC_PATCHLEVEL__

选项–H输出所有被使用头文件的嵌套链,及缺失多次包含防卫的头文件列表。这个选项也可写作--trace-includes

对于选项–I path,则调用add_path来处理这个参数。这个包含路径的信息由如下定义的cpp_dir结构来保存。

 

402  struct cpp_dir                                                                                             in cpplib.h

403  {

404   /* NULL-terminated singly-linked list.  */

405    struct cpp_dir *next;

406 

407    /* NAME of the directory, NUL-terminated.  */

408    char *name;

409    unsigned int len;

410 

411    /* One if a system header, two if a system header that has extern

412      "C" guards for C++.  */

413    unsigned char sysp;

414 

415    /* Mapping of file names for this directory for MS-DOS and related

416      platforms. A NULL-terminated array of (from, to) pairs.  */

417    const char **name_map;

418 

419   /* The C front end uses these to recognize duplicated

420      directories in the search path.  */

421    ino_t ino;

422    dev_t dev;

423  };

 

在系统中,被包含的头文件可分为4类。其一是由“”包含,而另一种由<>包含,再者表示为系统头文件,最后则由选项-idirafter引入。因此在下面的代码中,headstails都是大小为4的数组。每一对通过分别指向头文件链表的头和尾,维护着一类头文件的路径。

 

303  void

304  add_path (char *path, int chain, int cxx_aware)                                            in c-inpath.c

305  {

306    struct cpp_dir *p;

307 

308  #if defined (HAVE_DOS_BASED_FILE_SYSTEM)

309    /* Convert all backslashes to slashes. The native CRT stat()

310      function does not recognise a directory that ends in a backslash

311      (unless it is a drive root dir, such "c:/"). Forward slashes,

312      trailing or otherwise, cause no problems for stat().  */

313    char* c;

314    for (c = path; *c; c++)

315      if (*c == '//') *c = '/';

316  #endif

317 

318    p = xmalloc (sizeof (struct cpp_dir));

319   p->next = NULL;

320    p->name = path;

321    if (chain == SYSTEM || chain == AFTER)

322      p->sysp = 1 + !cxx_aware;

323    else

324      p->sysp = 0;

325 

326    if (tails[chain])

327      tails[chain]->next = p;

328    else

329      heads[chain] = p;

330    tails[chain] = p;

331  }

 

上面的321行,在这里cxx_aware0,因此由-I-dirafter-isystem引入的查找路径皆认为其中包含的头文件,若要用于C++,需要extern “C”保护字段。而选项-I-表示不能在当前目录中查找源文件,编译命令中指定的除外。因此调用split_quote_chain来移除被“”引入的路径。注意到这里的代码有内存泄露的问题。

 

290  void

291  split_quote_chain (void)                                                                              in c-inpath.c

292  {

293    heads[QUOTE] = heads[BRACKET];

294    tails[QUOTE] = tails[BRACKET];

295    heads[BRACKET] = NULL;

296    tails[BRACKET] = NULL;

297   /* This is NOT redundant.  */

298    quote_ignores_source_dir = true;

299  }

 

上面c_common_handle_option305行,通过选项-M,预处理器会输出能用于makefile的规则。这个规则包括了目标文件名,冒号,源文件名及所包含的文件名。这些包含的文件名以全路径名分行列出。如果在命令行中有选项–include-imacros,这些选项引入的文件名也被列出。选项-M隐含选项-E

产生的规则包含目标文件名及依赖列表(the list of dependencies),但不包括编译源文件的规则。除非使用选项-MT-MQ来指明名字,规则中的目标文件名与输入源文件名相同,只是更换了后缀。

其他涉及生成makefile规则的预处理选项有-MD-MMD-MF-MG-MM-MP-MQ-MT

而在311行,-MM类似于–M,只是不列出系统头文件。

对于选项–MG,它与-M-MM连用表示,缺失的头文件可被视为需要生成的文件,这些文件与源文件在同一目录下。而产生的依赖列表则假定这些头文件都存在而且不包含其他头文件。

选项–MP,与-M-MM连用,将为每个包含的文件产生一个假目标(dummy target)。这样做的唯一目的是,当移除头文件而没更新makefile时,防止make产生错误消息(头文件会由假目标生成)。

接下来在323行,deps_seen表示是否遇到了-MF选项。–MF filename,当与-M-MM-MD,或-MMD连用,这个选项指定了要写入依赖关系的文件名。另一个指定这个输出文件名的方法是设定环境变量DEPENDENCIES_OUTPUT

另在337行,选项-MQ target类似于-MT,除了目标名,因为makefile的缘故,被适当地引用起来(quoted appropriately)。例如,命令gcc -M –MQ '$(OBJMRK)mrk.o' brink.c将产生如下规则:

$$(OBJMRK)mrk.o: brink.c

–MT target,与-M-MM连用,则指明生成的makefile规则中的目标文件名。默认的,目标文件名与输入源文件名一致,并具有后缀.o。选项-MT可以用来指定一个不同的名字,一个全路径名或者基于一个环境变量的名字。例如,命令gcc -M -MT '$(OBJMRK)mrk.o' brink.c将产生如下规则:

$(OBJMRK)mrk.o: brink.c

flag_no_line_commands-P)如果非0,在使用-E选项时,预处理器不产生#line指示(directives)。

348行,flag_working_directory-fworking-directory)如果非0,表示我们不希望预处理器在当前工作目录下产生line指示(directives);如果是1,则表示我们希望它如此;而-1则表示我们需要根据是否产生了调试信息来决定(默认值为-1)。

对于–Umacro,如果macro之前已被定义,该宏的定义被移除。所有的-D选项都在-U选项前被处理,而所有的-U选项则在-include-imacros选项前得到处理。这个选项的处理被推迟到c_common_post_options

356行,warn_abi-Wabi)如果非0,表示警告那些由符合ABI的编译器编译时,会发生改变的部分(默认值为0)。【6】给出了G++不符合ABI的地方,但以我所测试的结果,这些不符合的地方,在当前版本已经得到修正。

 

c_common_handle_option (continue)

 

327      case OPT_MG:

328        deps_seen = true;

329        cpp_opts->deps.missing_files = true;

330        break;

331 

332      case OPT_MP:

333        deps_seen = true;

334        cpp_opts->deps.phony_targets = true;

335        break;

336 

337      case OPT_MQ:

338      case OPT_MT:

339        deps_seen = true;

340        defer_opt (code, arg);

341        break;

342 

343      case OPT_P:

344        flag_no_line_commands = 1;

345        break;

346 

347      case OPT_fworking_directory:

348        flag_working_directory = value;

349        break;

350 

351      case OPT_U:

352        defer_opt (code, arg);

353        break;

354 

355      case OPT_Wabi:

356        warn_abi = value;

357        break;

358 

359      case OPT_Wall:

360        set_Wunused (value);

361       set_Wformat (value);

362        set_Wimplicit (value);

363        warn_char_subscripts = value;

364        warn_missing_braces = value;

365        warn_parentheses = value;

366        warn_return_type = value;

367        warn_sequence_point = value;   /* Was C only.  */

368        if (c_dialect_cxx ())

369          warn_sign_compare = value;

370        warn_switch = value;

371        warn_strict_aliasing = value;

372 

373        /* Only warn about unknown pragmas that are not in system

374          headers.  */

375        warn_unknown_pragmas = value;

376 

377        /* We save the value of warn_uninitialized, since if they put

378          -Wuninitialized on the command line, we need to generate a

379          warning about not using it without also specifying -O.  */

380        if (warn_uninitialized != 1)

381          warn_uninitialized = (value ? 2 : 0);

382 

383        if (!c_dialect_cxx ())

384          /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding

385            can turn it off only if it's not explicit.  */

386          warn_main = value * 2;

387        else

388        {

389           /* C++-specific warnings.  */

390           warn_nonvdtor = value;

391           warn_reorder = value;

392           warn_nontemplate_friend = value;

393        }

394 

395        cpp_opts->warn_trigraphs = value;

396        cpp_opts->warn_comments = value;

397        cpp_opts->warn_num_sign_change = value;

398        cpp_opts->warn_multichar = value;  /* Was C++ only.  */

399        break;

 

对于–Wall选项,注意到360行的value表示选项是否为否定义(0为否定义,1为其他,见handle_option)。在这里value1

 

1572 void

1573 set_Wunused (int setting)                                                                                  in opts.c

1574 {

1575   warn_unused_function = setting;

1576   warn_unused_label = setting;

1577   /* Unused function parameter warnings are reported when either

1578     ``-Wextra -Wunused'' or ``-Wunused-parameter'' is specified.

1579     Thus, if -Wextra has already been seen, set warn_unused_parameter;

1580     otherwise set maybe_warn_extra_parameter, which will be picked up

1581     by set_Wextra.  */

1582   maybe_warn_unused_parameter = setting;

1583   warn_unused_parameter = (setting && extra_warnings);

1584   warn_unused_variable = setting;

1585   warn_unused_value = setting;

1586 }

 

因此上面,所有关于警告未使用项目的标识都被设为真。在1583行,extra_warnings由选项–W/-Wextra设置。

 

36    void

37    set_Wformat (int setting)                                                                            in c-format.c

38    {

39      warn_format = setting;

40      warn_format_extra_args = setting;

41      warn_format_zero_length = setting;

42      if (setting != 1)

43      {

44        warn_format_nonliteral = setting;

45        warn_format_security = setting;

46        warn_format_y2k = setting;

47      }

48      /* Make sure not to disable -Wnonnull if -Wformat=0 is specified.  */

49      if (setting)

50        warn_nonnull = setting;

51    }

 

上面,warn_format-Wformat)如果非0,在调用格式化I/O函数(printfscanfstrftimestrfmon)时,警告异常的格式/参数对。

warn_format_extra_argsCC++ObjC-Wformat-extra-args)如果非0,警告格式中多余的参数。

warn_format_zero_length-Wformat-zero-length)如果非0而且也指定了-Wformat,警告长度为0的格式字符串。

warn_format_nonliteralCC++ObjC-Wformat-nonliteral)如果非0,警告非文字(non-literal)的格式参数(format arguments)。

warn_format_securityCC++ObjC-Wformat-security)如果非0而且也指定了-Wformat,警告对诸如printfscanf的调用所存在的安全问题。把变量而不是字符串常量用于格式的函数调用是不安全的,因为它可能包含%n

 warn_format_y2kCC++ObjC-Wformat-y2k)如果非0,警告strftime格式中的Y2K 问题。

warn_nonnull如果分0,警告把NULL传给标记为要求非NULL的参数。

 

1559 static void

1560 set_Wimplicit (int on)                                                                                in c-opts.c

1561 {

1562   warn_implicit = on;

1563   warn_implicit_int = on;

1564   if (on)

1565   {

1566     if (mesg_implicit_function_declaration != 2)

1567       mesg_implicit_function_declaration = 1;

1568   }

1569   else

1570     mesg_implicit_function_declaration = 0;

1571 }

 

上面,warn_implicit如果非0,警告隐式的声明。

warn_implicit_intC-Wimplicit-int)如果非0,警告使用隐式声明的int。这个选项也可由-Wimplicit-Wall设置。

mesg_implicit_function_declarationC-Wimplicit-function-declaration)如果非0,表示对使用隐式函数声明的给出消息;为1时表示给出警告,为2时给出错误。这个选项也可由-Wimplicit-Wall设置。

c_common_handle_option363行,warn_char_subscriptCC++ObjC-Wchar-subscripts)如果非0,警告下标具有char类型。因为char经常默认为有符号,这可能会导致错误。

warn_missing_bracesCC++ObjC-Wmissing-braces,也由-Wall设置)如果非0且一个数组的初始化数值没有完全括起来时,给出警告。在下面的例子中,数组ab都正确初始化了,但b所用的大括号更具体地指明了值的去处:

int a[2][2] = { 0, 1, 2, 3 };

int b[2][2] = { { 1, 2 }, { 3, 4} };

warn_parenthesesCC++ObjC-Wparentheses,也由-Wall设置)如果非0警告那些虽然语法上是正确的,但由于操作符的优先级或代码的结构,可能给编程的人带来混乱的代码构造。

以下的表达式将导致一个警告,因为程序员很难记住逻辑操作符是左结合还是右结合的,有可能他记错了:

if(a && b || c) . . .

而下面给出警告是因为,在缺少大括号时,ifelse语句间的关系可能不是程序员设想的那样:

if(a)

if(b)

m = p;

else

a = 0;

从缩进来看,程序员的意图是else语句对应于第一个if语句,但实际不是这样。

warn_return_typeCC++-Wreturn-type,也由-Wall设置)如果非0,警告没有定义返回值或者定义了空返回值而返回了void以外的类型的函数定义。

warn_sequence_pointC-Wsequence-point,也由-Wall设置)如果非0,警告在一个表达式中一个变量被引用多次,而且其中一次修改其值。在C语言中,允许表达式在序列点间(between sequence points)以任意次序求值(只要操作符的优先级不变),因此在一处修改一个变量而在另一处使用它,会使得其值不确定。序列点(sequence point)由下列操作符在代码中指出:

; , && || ? :

以下是一些违反序列点规则,而导致不确定结果的表达式例子:

s = a[s++];

s = s--;

a[s++] = b[s];

a[s] = b[s += c];

warn_sign_compareCC++ObjC-Wsign-compare,也由-Wall设置)如果非0,警告有符号及无符号值间的比较。如果为-1-Wsign-compare-Wno-sign-compare都没指明使用(这时,由-Wextra来决定)。

warn_switchCC++ObjC-Wswitch,也由-Wall设置)如果非0,警告一个使用enumswitch,没有default事件,不是所有enum值都有对应事件(case)。

warn_strict_aliasing-Wstrict-aliasing,依赖被编译的语言,应用最严格的别名规则(the strictest aliasing rules)。在C中,在严格别名下,例如,一个int不能是一个double或指针的别名,但可以是一个unsigned int的别名。即便是严格别名,对于union的数据成员,这都不是问题,只要这些引用是通过union本身,而不是通过指向其地址的指针。下面的代码会有问题。

int *iptr;

union {

int ivalue;

double dvalue;

} migs;

. . .

migs.ivalue = 45;

iptr = &migs.ivalue;

frammis(*iptr);

migs.dvalue = 88.6;

frammis(*iptr);

在这个例子中,很可能严格别名不能识别到iptr指向的值在2个函数调用间被改变了。但直接访问union成员就没有这个问题。

warn_unknown_pragmas-Wunknown-pragmas,也由-Wall设置)如果非0,警告不能识别的#pragma指示(directive)。

warn_uninitialized-Winitialized)如果非0,警告一个自动变量未初始化就被使用了。同样警告会破坏自动变量的setjmp调用。这个选项仅能与-O连用,因为要检测这些情况,需要数据流优化信息(the optimizing data flow information)。

因为这个选项要求数据流分析,因此它不可能完全正确。例如,下面的代码中,不可能保证在printf语句前value一定有或一定没有初始化:

int value;

if(a < b)

value = 5;

else if(a > c)

value = 10;

printf("%d/n",value);

因为数据流分析的本质,这个选项不会用于结构体,union,数组,任一声明为volatile的变量,任一被取地址的变量,或任一用作计算从不使用的值的变量。数据流分析能识别setjmp语句,但它没办法知道何处longjmp被调用,因此当没有问题时,依然给出警告。

这个选项当-O被使用时,由-Wall设置。

warn_mainCC++-Wmain)如果非0,警告可疑的main函数。

warn_nonvdtorC++-Wnon-virtual-dtor,也由-Wall设置)如果非0,警告一个类应该有虚析构函数,而实无。

warn_reorderC++-Wreorder,也由-Wall设置)如果非0警告编译器重新安排类成员,以符合其声明次序。例如,下面的初始化数据将被重新排列:

class Reo {

int i;

int j;

Reo(): j(5), i(10) { }

};

warn_nontemplate_friendC++-Wnon-template-friend,也由-Wall设置)如果非0,警告在一个模板中声明了一个非模板化(non-templatized)的友元函数。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值