??xml version="1.0" encoding="utf-8" standalone="yes"?>
在函数声明中Q?br>无论是Cq是在C++Q都可以省略形式参数名?br>但是Q通常?strong>?/span>省略形式参数名?br>
在函数定义中Q?br>1. 当需要用Ş式参数的时候,昄Q必ȝ形式参数命名?br>
2. 当不需要用Ş式参数的时候,C与C++有微差异:(x)
—?C不能省略形式参数?/strong>Q?即不用?br>—?C++可以省略形式参数?/strong>Q?strong style="COLOR: red">如果不用?br>—?q且在C++中,如果l不使用的Ş式参数命名,可能?x)得C?strong>警告?br>
二、示例:(x)
void greeting_omit(const char* name);
void greeting_unuse(const char* name);
void greeting_nowarning(const char* name);
int main(void) {
greeting_omit("");
greeting_unuse("");
greeting_nowarning("");
(void)getchar();
return 0;
}
三、三个函数分别实现如下:(x)
三?
printf("hello world\n");
}
——在C中是错误Q?br>1. msvc :
error C2055: expected formal parameter list, not a type list
error C2055: 应输入Ş参表Q而不是类型表
2. gcc : Q报错更清晰一些)
error: parameter name omitted
错误Q?省略参数?br>
——在C++中正,且无警告?br>
三?
printf("hello Cherrie\n");
}
在C和C++中都正确Q但可能得到一个警告:(x)
1. msvc :
warning C4100: 'name' : unreferenced formal parameter
warning C4100: “name”: 未引用的形参
2. gcc :
warning: unused parameter 'name'
警告Q?未用的参数‘name’
在gcc中,打开q个警告的选项?strong>-Wunused-parameter?br>该选项包含?Wall中?br>
三?
(void)name;
printf("hello OwnWaterloo\n");
}
在C和C++中都正确Qƈ且无警告?br>
相关链接Q?br>
——示例代?br>http://immature.googlecode.com/svn/trunk/iMmature/sample/omit_parameter_name
?span rel="dc:type" xmlns:dc="http://purl.org/dc/elements/1.1/">作品采用知识׃n|名-非商业性?相同方式׃n 2.5 中国大陆许可协议q行许可?
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?6?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html
C++标准规定Qmain函数可以省略q回语句Q等效于q回0?br>
5. A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling exit with the return value as the argument.
If control reaches the end of main without encountering a return statement, the effect is that of executing
return 0;
——ISO C++03 3.6.1 Main function p44/72
——ISO C++98 3.6.1 Main function p43/69
注意Q?br>1. main函数的返回类型是intQ?不是void或者其他类型?br>2. 该规?strong>仅仅对main函数适用?br>3. 对其他函敎ͼ如果省略q回| 得C?strong>警告?br>4. 应该避免3的情c?br>
三? 汇编代码
更严谨的验证Ҏ(gu)是查看汇~代码?br>
可以看到Q在minimalist与omit_return_in_main的main函数中都有将eax|?的代码?br>在omit_return_in_other中的not_main函数中,没有q样的代码?/p>
?span xmlns:dc="http://purl.org/dc/elements/1.1/" rel="dc:type">作品采用知识׃n|名-非商业性?相同方式׃n 2.5 中国大陆许可协议q行许可?
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?6?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?1?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html
通常直接使用va_start的函敎ͼ假设?strong>fQ的实现体会(x)很短。:(x) 也难保它不会(x)?span style="COLOR: #ff0000">遗忘
1. ?span style="COLOR: #ff00ff">va_start初始?span style="COLOR: #0000ff">va_list
2. 调用一个?strong>va_list参数的函敎ͼ假设?strong>vfQ?br>Qvf 是一个固定参数列表的函数Q?br>
因ؓ(f)f的实C非常短, 一眼望Iѝ?br>所以你能确保vfq回后, ap不会(x)再被你用?br>
因此Q?ap|空除了费CPU周期Q?没有实际意义Q?是这样吗Q?br>
一?. ~译器参与优?br>
你能发现代码末尾ap不再被用, va_end其|空毫无意义?br>那么Q你的编译器能发现这个问题么Q?br>
h证一下?br>如果~译器也知道Q?q且没有为va_end生成M代码Q?那么省略va_end是不必要的了?br>
一?. ~译器不参与优化
你编译器真ؓ(f)va_end生成了无意义q且令h感到无法接受的机器码Ӟ该怎么办?
一?.1 你只在该~译器下工作
那么Q你省略va_end好了?br>但请不要宣扬一些带?strong>误导性质的言辞?br>当你?#8220;va_end是不需?#8221;的时候, 请附带说明:(x)
1. 你的q_
2. ?strong>?/span>考虑跨^?/strong>
一?.2 需要要考虑UL到其他编译器
注意Q?其他~译器包括(但不限于Q:(x)
——不?strong>架构上的~译?br>——相同架构上的不?strong>~译器?/strong>
——相同架构上的相同编译器产品?strong>不同版本?br>
需要分析在该编译器下,对va_end的处理是?strong>依然可以被省?/strong>?br>——显Ӟq是一?strong>乏味的工作?br>
即你在源代码中写入 Q?/p>
—?UL一个程序的时候有太多工作要做?br>q么一个不L(fng)的地方, ?x)被惌v来么Q?br>
如果在被UL的编译器上:(x)
1. 省略va_end导致函C能正常返回(见附录)
也许立马p发现q个bug?br>崩掉了嘛Q?当然要引?#8220;重视”?br>
2. 省略va_end不会(x)立马崩溃Q?而是D内存泄露Q见附录Q?br>情况很严重了?br>E序依然q行“良好”?br>但是调用一ơ函敎ͼ 泄漏一点点内存?br>
q恐怕就要花很多旉才能查出来了?br>如果目旉再紧一点, 也许Ҏ(gu)来不及修复q个bug发布了?br>反正漏得?#8220;不多”Q?你说是吧Q?br>
二?va_end能留则留
我们何不换个方式Q?
1. 坚持使用va_end
——即便我们心里清楚它没做什么有用的事情也是如此?br>
代码UL本质是Q?不对q_QCPU、OS、Compiler{等Q?span style="COLOR: #ff0000">依赖?br>stdarg是标准库提供的一U实现可变长参数列表?strong style="COLOR: #ff0000">可移?/strong>方式?br>我们没理由弃之不用?br>
如果我们在源代码中坚持用va_endQ?br>——至在q点上,׃?strong>对编译器产生依赖Q?strong>省略va_endQ就是一U?span style="COLOR: #ff0000">依赖Q?br>——移植的时候, 自然无须为其操心?br>
2. va_end令编译器产生?strong>令h无法接受?strong style="COLOR: #ff0000">无用代码?br>——通常Q这是不?x)发生的?~译器厂商会(x)考虑q个事情?br>
比如上面的va_end宏, ?x)生一ơ不必要的赋值操作, 但通常?x)被~译器优化ؓ(f)I?br>即没有被优化ؓ(f)I, 一ơ赋值操作, 真的是不可容忍的么Q?br>
如果实不能容忍Q?作ؓ(f)一U?strong>Ҏ(gu)情ŞQ?可以q样 Q?/p>
——可变长参数列表误区与陷阱——va_arg不可接受的类?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html
q是使用stdarg提供的功能需要遵守契U之一?br>契约本n仍然是简单的?br>契约背后的原理也许比较晦涩, 但也可以不必兛_?br>
我们Z个没有后~的文Ӟ叫nosuffixQ?写入如上内容?br>而且Q?我们也不需要编译出目标代码?br>只需要测试__cplusplus宏(见?a href="http://www.shnenglu.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html">预定义__cplusplus?/strong>》)是否存在Qƈ且用#error报告卛_?br> nosuffix .c .cpp .txt .C .CPP .cc .cxx .inl .c++ .cp gcc obj C C++ obj C++ C++ C++ C++ obj C++ C++ g++ obj C++ C++ obj C++ C++ C++ C++ obj C++ C++ cl obj C C++ obj C C++ C++ C++ obj obj obj 命o行:(x)
然后建立一些内容完全一L(fng)文gQ?/p>
q些文g共有10个:(x)
c.c?cpp.cpp、txt.txt、UC.C、UCPP.CPP、cc.cc、cxx.cxx、inl.inl、c++.c++、cp.cp?br>QUC和UCPP是ؓ(f)了测试大写后~名)
二?. 试Ҏ(gu)
对GCC使用Q?br>gcc(g++) filename >stdout.txt 2>stderr.txt
对MSVC使用Q?br>cl filename >stdout.txt 2>stderr.txt
二?. 试l果
gcc、g++、cl对以下后~名文件的默认操作如下?/a>Q?br>
对该表的几点说明Q?br>1. 表中的obj表示该条件下Q?l一E序它们认作目标文Ӟ q打执行链接工作?br>q显然是错误的, 因ؓ(f)他们包含的是文本?br>
2. gcc、g++Q编译代码)的区?br>GCC认ؓ(f)带有.c?cpp?C?CPP?cc?cxx?c++?cpQ但不限于)后缀的文件是C/C++源文件?br>gcc把带?c后缀的文Ӟ 当作C源文Ӟ 把带有其他后~名的文g当作C++源文件?br>g++带有上q所有后~的文Ӟ都当作C++源文件?br>
3. MSVC与GCC的区?br>MSVC认ؓ(f)带有.c?cpp?C?CPP?cc?cxx后缀的文件是C/C++源文件?br>上述GCC相比Q?排除?c++?cp
同时Qwindows下的文g名是不区分大写的, 所?c?CQ?cpp?CPP是一L(fng)?br>与GCC相比Q?.C不再认ؓ(f)是C++源文Ӟ 而是?c一样作为C源文件处理?br>
二?. 试结
׃表以及说明, 如果我们打算~写跨^台的代码Q?br>
1. 不推荐用的后缀?br>.c++?cp
——因为它们不被MSVC支持
.C
——因为MSVCq不区别对待.c?C
2. 可以使用的后~?br>——对C源文?br>可以使用.c?br>
——对C++源文?br>可以使用.cpp?cc?cxx?br>
—?CPP不推?br>因ؓ(f)在xnix?a.CPP与a.cpp?个文Ӟ 而复制到Windows上就发生重名?br>如果只?cpp可以避免该情况?br>
3. 关于.inl
有些文g内容实是C/C++代码Q?但是却不直接作ؓ(f)译单元Q而是被其他翻译单元包含?br>理论上说Q它们取M名字都没关系。但是将它们取ؓ(f).inl?x)得C些好处:(x)
—?nbsp; 暗示该文件包含C/C++代码
—?nbsp; 一些编辑器?x)对其按C/C++语法q行高亮?br>
三?昑ּ指定
有时候需要覆盖默认情况,昑ּ指定我们需要的操作?br>
三?. GCC “-x”
GCC通过-x选项昑ּ指定~译源代码的语言Q?br>-x cQ或-xcQ?br> —?nbsp; 源代码作ؓ(f)C源文件?br>-x c++、(?xc++Q?br> —?nbsp; 源代码作ؓ(f)C++源文件?br>
对于“?#8221;中的试Q?只要命令行改ؓ(f)Q?br>gcc(g++) -x c (-xc) filename
所有文仉被作ؓ(f)C源文件处理, q输?error !--- C ---!
而用如下命令行Q?br>gcc(g++) -x c++ (-xc++) filename
所有文仉被作ؓ(f)C++源文件处理, q输?error !--- C++ ---!
三?. MSVC “/TC” “/TP”
MSVC通过/TCQ?TPQ选项Q?昑ּ指定输入作为CQC++Q源代码?br>
?#8220;?#8221;中的试Q?命o行:(x)
cl /TC filename
Ҏ(gu)有文仉输?error !--- C --- !
cl /TP filename
Ҏ(gu)有文仉输?error !--- C++ ---!
四、ȝ
1. 使用“二?”中推荐的方式Q给源代码文件命名?br>2. 覆盖默认情况Q?x(GCC)或?TC?TPQMSVCQ?br>3. 带提一点, gcc、g++用作链接Ӟ 也有一些区别?br>链接C++Q或者C/C++混合Q目标代码, 推荐使用g++?br>因ؓ(f)GCC高版本中Q?gcc链接旉认不?x)导入C++需要的q行时库?br>
相关链接Q?br>
——源代码
http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/language
——?a href="http://www.shnenglu.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html">预定义__cplusplus?/a>?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html
?span xmlns:dc="http://purl.org/dc/elements/1.1/" rel="dc:type">作品采用知识׃n|名-非商业性?相同方式׃n 2.5 中国大陆许可协议q行许可?
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?0?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html
代码很简单:(x)
如果没有定义__cplusplusQ?那么当前源代码被当作C源代码处理?br>如果定义了__cplusplusQ那么当前源代码被当中C++源代码处理, q且输出__cplusplus宏被展开后的字符丌Ӏ?br>
CZ2Q?/p>
q段代码更简单了Q?只是使用了__cplusplus宏?br>然后查看预处理(见?a href="http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html">查看源文仉处理l果》)Q看其被扩展后的l果?br>
可以看到Q?__GUNC__ 宏最l被扩展为整数字面量3QGCC 3Q?br>
如果源代码很长, 输出到命令行H口中查看也怸方便?br>如何其输出C个文件中呢?
一.1.1?重定?br>
因ؓ(f)-E是输出到stdoutQ?昄可以其重定向到另一个文Ӟ 如执行如下命令:(x)
gcc -E preprocess_only.c >stdout.txt
那么stdout.txt中, p得到刚才命o行窗口中的内宏V?br>
一.1.2?-o Q小写) 选项
-o选项用于指定出文件名?br>对于-cQ?-o指定的是目标文g名?br>对于-S Q?o指定的是汇编文g名?br>对于-EQ?-o自然也可以指定预处理文g名, 如执行如下命令:(x)
gcc -E preprocess_only.c -o output.txt
那么output.txt中会(x)得到“一.1.1”中的stdout.txt?#8220;一.1”中控制台H口一L(fng)l果?br>
一.2?save-temps 选项
-save-temps选项保?strong>中间文gQ如预处理后的结果文件、汇~代码文件与目标文g?br>其中的预处理l果文gQ通常?strong>.i后缀Q是我们所需要的?br>
举例Q?br>1?gcc -save-temps -E preprocess_only.c
0个中间文件?br>输出预处理结果, ?#8220;一.1”一P 输出到控制台H口中?br>Ҏ(gu)如下命oQ?br>
1.1?nbsp;gcc -save-temps -E preprocess_only.c -o temp_output.txt
1.2?gcc -save-temps -E preprocess_only.c >temp_output.txt
可以看出Q?-E选项不生中间文件?预处理结果就是最l结果?br>同时可以使用 -o选项或者重定向Q?把结果保存到一个文件中?br>
2?gcc -save-temps -S preprocess_only.c
1个中间文Ӟ(x) preprocess_only.iQ预处理l果Q?br>1个输出文Ӟ(x)preprocess_only.sQ汇~代码)
Ҏ(gu)如下命oQ?br>
2.1?gcc -save-temps -S preprocess_only.c -o unknown
得到preprocess_only.i文gQ内Ҏ(gu)预处理结果,是中间文件?br>得到unknown文gQ内Ҏ(gu)汇编代码Q?是最l结果文件?br>
3?gcc -save-temps -c preprocess_only.c
2个中间文Ӟ(x) preprocess_only.i与preprocess_only.s?br>1个输出文Ӟ(x) preprocess_only.oQ目标代码)
Ҏ(gu)如下命oQ?br>
3.1?gcc -save-temps -c preprocess_only.c -o unknown
得到preprocess_only.i ?preprocess_only.s文gQ内容分别是预处理结果与汇编代码Q是中间l果?br>unknown文gQ?内容是目标代码,是最l结果文件?br>
4?gcc -save-temps preprocess_only.c
3个中间文Ӟ(x) preprocess_only.i、preprocess_only.s、preprocess_only.o?br>1个输出文Ӟ(x) a.outQa.exe with mingwQ?br>Ҏ(gu)如下命oQ?br>
4.1?gcc -save-temps preprocess_only.c -o what
得到上述3个文Ӟ 是中间文件?br>what文gQwhat.exe with mingwQ, 内容是可执行代码Q?是最l结果文件?br>
可以看到Q?_MSC_VER宏最l被扩展为整数字面?200QVC6Q?br>
对于较长的源文gQ?我们同样希望结果输出到一个文件中?br>
?1.1、重定向
执行Q?br>cl /E preprocess_only.c >stdout.txt
stdout.txt保存上面的l果?br>
注意Q?在msvc中,没有“一.1.2”的对应物?br>执行Q?br>cl /help
在输Z扑ֈ-OUTPUT FILES-cdQ?可以看到没有命名预处理结果的方式。有两个怼的选项Q?br>/Fe 命名可执行文件?br>/Fp 命名预编译头文g?br>但不是我们需要的选项?br>
也许VC认ؓ(f)通过 “/E + 重定?#8221;可以达到命名输出文件的目的?br>所以就没有设计辑ֈ此目的的另一U方法?br>
?2?P 选项
/P preprocess to file
/P 预处理到文g
执行Q?br>cl /P preprocess_only.c
得?preprocess_only.i
/P?x)将?nbsp;xxx.suffix 的预处理l果输出?xxx.i 文g中?br>没有指定文g名的方式?如果需?strong>指定输出文g?/strong>Q?可以使用 “/E + 重定?#8221;
?3 /EP 选项
/E?P选项都将保留一部分Q源文gQ行信息Q如“?1”所C?br>如果q是不需要的Q?可以使用 /EP选项?br>
/EP preprocess to stdout, no #line
/EP 预处理到标准输出Q没?#line
如:(x)
cl /EP preprocess_only.c
得到如下输出:(x)
同样Q?如果需要输出到指定文gQ?可以使用重定?/strong>?br>
?4 其他一些有的选项
1. /C Q大写)
don't strip commentsQ不抽出注释Q?br>如果保留注释对理解预处理l果有帮助, 可以使用q个选项?br>
2. /U /u
/u remove all predefined macros
/u U除所有预定义的宏
/U<name> remove predefined macro
/U<name> U除预定义的?br>
比如可以通过Q?br>cl /u preprocess_only.c
cl /U_MSC_VER preprocess_only.c
来得C?unknown complier错误?#8230;…
3. /D
/D<name>{=|#}<text> define macro
/D<name>{=|#}<text> 定义?br>
可以通过Q?br>cl /D__GUNC__=3 preprocess_only.c
来假装gcc~译器囧……
相关链接Q?br>
——示例文件下?br>http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/preprocess_only/
http://www.shnenglu.com/Files/ownwaterloo/preprocess_only.zip
——《配|msvc命o行环境?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html
——《配|msvc命o行环?l?——编写msvc~译脚本?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html
——《预定义_MSC_VER宏?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html
——《预定义__GNUC__宏?br>http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html
?span xmlns:dc="http://purl.org/dc/elements/1.1/" rel="dc:type">作品采用知识׃n|名-非商业性?相同方式׃n 2.5 中国大陆许可协议q行许可?
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?6?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/preprocess_only.html
--------------------------------------------------------------------------------
一般来_ 可以在命o行下使用cl了?br>
cl文g版本与VS版本、VC产品版本、_MSC_VER宏的对应关系如下?/a>Q?/p>
VS版本 |
VC产品版本?/p> |
cl文g版本?/p> |
_MSC_VER宏的?/p> |
98 |
6.x |
12.x |
1200 |
2005 |
8.x |
14.x |
1400 |
2008 |
9.x |
15.x |
1500 |
——?a >IDE 不是E序员的唯一选择Q一Q?/strong>?br>http://blog.codingnow.com/2008/09/replacement_of_ide_1.html
?span rel="dc:type" xmlns:dc="http://purl.org/dc/elements/1.1/">作品采用知识׃n|名-非商业性?相同方式׃n 2.5 中国大陆许可协议q行许可?br>
转蝲h?Q?br>文章作?- OwnWaterloo
发表旉 - 2009q?4?5?br>原文链接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html