您正在查看: php 分类下的文章

关于PHP curl上传文件或者图片问题

最近用到php5.6 的curl上传图片,但是接口一致返回参数失败,一直没有找到原因。最后看文档才找到原因,是因为不同的php版本,参数设置不一样。

不同版本PHP之间cURL的区别

PHP的cURL支持通过给CURL_POSTFIELDS传递关联数组(而不是字符串)来生成multipart/form-data的POST请求。

传统上,PHP的cURL支持通过在数组数据中,使用“@+文件全路径”的语法附加文件,供cURL读取上传。这与命令行直接调用cURL程序的语法是一致的:

curl_setopt(ch, CURLOPT_POSTFIELDS, array(
    'file' => '@'.realpath('av.png'), 
)); 
equals
$ curl -F "file=@/path/av.png" 

但PHP从5.5开始引入了新的CURLFile类用来指向文件。CURLFile类也可以详细定义MIME类型、文件名等可能出现在multipart/form-data数据中的附加信息。PHP推荐使用CURLFile替代旧的@语法:

curl_setopt(ch, CURLOPT_POSTFIELDS, [
    'file' => new CURLFile(realpath('av.png')), 
]); 

PHP 5.5另外引入了CURL_SAFE_UPLOAD选项,可以强制PHP的cURL模块拒绝旧的@语法,仅接受CURLFile式的文件。5.5的默认值为false,5.6的默认值为true。

但是坑的一点在于:@语法在5.5就已经被打了deprecated,在5.6中就直接被删除了(会产生 ErorException: The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead)。

对于PHP 5.6+而言,手动设置CURL_SAFE_UPLOAD为false是毫无意义的。根本不是字面意义理解的“设置成false,就能开启旧的unsafe的方式”——旧的方式已经作为废弃语法彻底不存在了。PHP 5.6+ == CURLFile only,不要有任何的幻想。

我的部署环境是5.4(仅@语法),但开发环境是5.6(仅CURLFile)。都没有压在5.5这个两者都支持过渡版本上,结果就是必须写出带有环境判断的两套代码。

代码应该回归本源。我们的实际需求其实是:有CURLFile就优先采用,没有再退化到传统@语法。那么代码就来了:

if (class_exists('CURLFile')) {
    $field = array('fieldname' => new \CURLFile(realpath($filepath)));
} else {
    $field = array('fieldname' => '@' . realpath($filepath));
}

从可靠的角度,推荐指定CURL_SAFE_UPLOAD的值,明确告知php是容忍还是禁止旧的@语法。注意在低版本PHP中CURLOPT_SAFE_UPLOAD常量本身可能不存在,需要判断:

if (class_exists('CURLFile')) {
    curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
} else {
    if (defined('CURLOPT_SAFE_UPLOAD')) {
        curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
    }
}

cURL选项设置的顺序 ()

curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);这条语句一定要在CURLOPT_POSTFIELDS之前设置

不管是curl_setopt()单发还是curl_setopt_array()批量,cURL的选项总是设置一个生效一个,而设置好的选项立刻就会影响cURL在设置后续选项时的行为。

例如CURLOPT_SAFE_UPLOAD就和CURLOPT_POSTFIELDS的行为有关。如果先设置CURLOPT_POSTFIELDS再设置CURLOPT_SAFE_UPLOAD,那么后者的约束作用就不会生效。因为设置前者时cURL就已经把数据实际的识读处理完毕了!

cURL有那么几个选项存在这种坑,务必小心。还好这种存在“依赖关系”的选项不多,机制也不复杂,简单处理即可。我的方法是先批量设置所有的选项,然后直到curl_exec()的前一刻才用curl_setopt()单发设置CURLOPT_POSTFIELDS。

实际上在curl_setopt_array()用的数组中,保证CURLOPT_POSTFIELDS的位置在后边也是可靠的。PHP的关联数组是有顺序保障的,我们也可以假设curl_setopt_array()内部的执行顺序一定是从头到尾按顺序[注A],所以尽可放心。

gcc,g++-GNU工程的C和C++编译器

NAME
gcc,g++-GNU工程的C和C++编译器(egcs-1.1.2)
总览(SYNOPSIS)
gcc[option|filename ]... g++[option|filename ]...
警告(WARNING)
本手册页内容摘自GNU C编译器的完整文档,仅限于解释选项的含义.
除非有人自愿维护,否则本手册页不再更新.如果发现手册页和软件之间有所矛盾,请查对Info文件, Info文件是权威文档.
如果我们发觉本手册页的内容由于过时而导致明显的混乱和抱怨时,我们就停止发布它.不可能有其他选择,象更新Info文件同时更新man手册,因为其他维护GNU CC的工作没有留给我们时间做这个. GNU工程认为man手册是过时产物,应该把时间用到别的地方.
如果需要完整和最新的文档,请查阅Info文件gcc'或Using and Porting GNU CC (for version 2.0) (使用和移植GNU CC 2.0) 手册.二者均来自Texinfo原文件gcc.texinfo. 描述(DESCRIPTION) C和C++编译器是集成的.他们都要用四个步骤中的一个或多个处理输入文件: 预处理(preprocessing),编译(compilation),汇编(assembly)和连接(linking).源文件后缀名标识源文件的语言,但是对编译器来说,后缀名控制着缺省设定: gcc 认为预处理后的文件(.i)是C文件,并且设定C形式的连接. g++ 认为预处理后的文件(.i)是C++文件,并且设定C++形式的连接. 源文件后缀名指出语言种类以及后期的操作: .c C源程序;预处理,编译,汇编 .C C++源程序;预处理,编译,汇编 .cc C++源程序;预处理,编译,汇编 .cxx C++源程序;预处理,编译,汇编 .m Objective-C源程序;预处理,编译,汇编 .i 预处理后的C文件;编译,汇编 .ii 预处理后的C++文件;编译,汇编 .s 汇编语言源程序;汇编 .S 汇编语言源程序;预处理,汇编 .h 预处理器文件;通常不出现在命令行上 其他后缀名的文件被传递给连接器(linker).通常包括: .o 目标文件(Object file) .a 归档库文件(Archive file) 除非使用了-c, -S,或-E选项(或者编译错误阻止了完整的过程),否则连接总是最后的步骤.在连接阶段中,所有对应于源程序的.o文件, -l库文件,无法识别的文件名(包括指定的.o目标文件和.a库文件)按命令行中的顺序传递给连接器. 选项(OPTIONS) 选项必须分立给出:-dr'完全不同于-d -r '. 大多数-f'和-W'选项有两个相反的格式: -fname和-fno-name (或-Wname和-Wno-name).这里只列举不是默认选项的格式. 下面是所有选项的摘要,按类型分组,解释放在后面的章节中. 总体选项(Overall Option) -c -S -E -o file -pipe -v -x language 语言选项(Language Option) -ansi -fall-virtual -fcond-mismatch -fdollars-in-identifiers -fenum-int-equiv -fexternal-templates -fno-asm -fno-builtin -fhosted -fno-hosted -ffreestanding -fno-freestanding -fno-strict-prototype -fsigned-bitfields -fsigned-char -fthis-is-variable -funsigned-bitfields -funsigned-char -fwritable-strings -traditional -traditional-cpp -trigraphs 警告选项(Warning Option) -fsyntax-only -pedantic -pedantic-errors -w -W -Wall -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscript -Wcomment -Wconversion -Wenum-clash -Werror -Wformat -Wid-clash-len -Wimplicit -Wimplicit-int -Wimplicit-function-declaration -Winline -Wlong-long -Wmain -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Wno-import -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wshadow -Wstrict-prototypes -Wswitch -Wtemplate-debugging -Wtraditional -Wtrigraphs -Wuninitialized -Wunused -Wwrite-strings 调试选项(Debugging Option) -a -dletters -fpretend-float -g -glevel -gcoff -gxcoff -gxcoff+ -gdwarf -gdwarf+ -gstabs -gstabs+ -ggdb -p -pg -save-temps -print-file-name=library -print-libgcc-file-name -print-prog-name=program 优化选项(Optimization Option) -fcaller-saves -fcse-follow-jumps -fcse-skip-blocks -fdelayed-branch -felide-constructors -fexpensive-optimizations -ffast-math -ffloat-store -fforce-addr -fforce-mem -finline-functions -fkeep-inline-functions -fmemoize-lookups -fno-default-inline -fno-defer-pop -fno-function-cse -fno-inline -fno-peephole -fomit-frame-pointer -frerun-cse-after-loop -fschedule-insns -fschedule-insns2 -fstrength-reduce -fthread-jumps -funroll-all-loops -funroll-loops -O -O2 -O3 预处理器选项(Preprocessor Option) -Aassertion -C -dD -dM -dN -Dmacro[=defn] -E -H -idirafter dir -include file -imacros file -iprefix file -iwithprefix dir -M -MD -MM -MMD -nostdinc -P -Umacro -undef 汇编器选项(Assembler Option) -Wa,option 连接器选项(Linker Option) -llibrary -nostartfiles -nostdlib -static -shared -symbolic -Xlinker option -Wl,option -u symbol 目录选项(Directory Option) -Bprefix -Idir -I- -Ldir 目标机选项(Target Option) -b machine -V version 配置相关选项(Configuration Dependent Option) M680x0 选项-m68000 -m68020 -m68020-40 -m68030 -m68040 -m68881 -mbitfield -mc68000 -mc68020 -mfpa -mnobitfield -mrtd -mshort -msoft-float VAX选项-mg -mgnu -munix SPARC选项-mepilogue -mfpu -mhard-float -mno-fpu -mno-epilogue -msoft-float -msparclite -mv8 -msupersparc -mcypress Convex选项-margcount -mc1 -mc2 -mnoargcount AMD29K选项-m29000 -m29050 -mbw -mdw -mkernel-registers -mlarge -mnbw -mnodw -msmall -mstack-check -muser-registers M88K选项-m88000 -m88100 -m88110 -mbig-pic -mcheck-zero-division -mhandle-large-shift -midentify-revision -mno-check-zero-division -mno-ocs-debug-info -mno-ocs-frame-position -mno-optimize-arg-area -mno-serialize-volatile -mno-underscores -mocs-debug-info -mocs-frame-position -moptimize-arg-area -mserialize-volatile -mshort-data-num -msvr3 -msvr4 -mtrap-large-shift -muse-div-instruction -mversion-03.00 -mwarn-passed-structs RS6000选项-mfp-in-toc -mno-fop-in-toc RT选项-mcall-lib-mul -mfp-arg-in-fpregs -mfp-arg-in-gregs -mfull-fp-blocks -mhc-struct-return -min-line-mul -mminimum-fp-blocks -mnohc-struct-return MIPS选项-mcpu=cpu type -mips2 -mips3 -mint64 -mlong64 -mmips-as -mgas -mrnames -mno-rnames -mgpopt -mno-gpopt -mstats -mno-stats -mmemcpy -mno-memcpy -mno-mips-tfile -mmips-tfile -msoft-float -mhard-float -mabicalls -mno-abicalls -mhalf-pic -mno-half-pic -G num -nocpp i386选项-m486 -mno-486 -msoft-float -mno-fp-ret-in-387 HPPA选项-mpa-risc-1-0 -mpa-risc-1-1 -mkernel -mshared-libs -mno-shared-libs -mlong-calls -mdisable-fpregs -mdisable-indexing -mtrailing-colon i960选项-mcpu-type -mnumerics -msoft-float -mleaf-procedures -mno-leaf-procedures -mtail-call -mno-tail-call -mcomplex-addr -mno-complex-addr -mcode-align -mno-code-align -mic-compat -mic2.0-compat -mic3.0-compat -masm-compat -mintel-asm -mstrict-align -mno-strict-align -mold-align -mno-old-align DEC Alpha选项-mfp-regs -mno-fp-regs -mno-soft-float -msoft-float System V选项-G -Qy -Qn -YP,paths -Ym,dir 代码生成选项(Code Generation Option) -fcall-saved-reg -fcall-used-reg -ffixed-reg -finhibit-size-directive -fnonnull-objects -fno-common -fno-ident -fno-gnu-linker -fpcc-struct-return -fpic -fPIC -freg-struct-return -fshared-data -fshort-enums -fshort-double -fvolatile -fvolatile-global -fverbose-asm 总体选项(Overall Option) -x language 明确指出后面输入文件的语言为language (而不是从文件名后缀得到的默认选择).这个选项应用于后面所有的输入文件,直到遇着下一个-x'选项. language的可选值有c',objective-c', c-header',c++', cpp-output',assembler',和assembler-with-cpp'. -x none 关闭任何对语种的明确说明,因此依据文件名后缀处理后面的文件(就象是从未使用过-x'选项).
如果只操作四个阶段(预处理,编译,汇编,连接)中的一部分,可以使用-x'选项(或文件名后缀)告诉gcc从哪里开始,用-c', -S',或-E'选项告诉gcc到哪里结束.注意,某些选项组合(例如, -x cpp-output -E')使gcc不作任何事情. -c 编译或汇编源文件,但是不作连接.编译器输出对应于源文件的目标文件. 缺省情况下, GCC通过用.o'替换源文件名后缀.c',.i', .s',等等,产生目标文件名.可以使用-o选项选择其他名字. GCC忽略-c选项后面任何无法识别的输入文件(他们不需要编译或汇编). -S 编译后即停止,不进行汇编.对于每个输入的非汇编语言文件,输出文件是汇编语言文件. 缺省情况下, GCC通过用.o'替换源文件名后缀.c',.i',等等,产生目标文件名.可以使用-o选项选择其他名字.
GCC忽略任何不需要编译的输入文件.
-E
预处理后即停止,不进行编译.预处理后的代码送往标准输出.
GCC忽略任何不需要预处理的输入文件.
-o file
指定输出文件为file.该选项不在乎GCC产生什么输出,无论是可执行文件,目标文件,汇编文件还是预处理后的C代码.
由于只能指定一个输出文件,因此编译多个输入文件时,使用-o'选项没有意义,除非输出一个可执行文件. 如果没有使用-o'选项,默认的输出结果是:可执行文件为a.out',source.suffix '的目标文件是source.o',汇编文件是source.s',而预处理后的C源代码送往标准输出.
-v
(在标准错误)显示执行编译阶段的命令.同时显示编译器驱动程序,预处理器,编译器的版本号.
-pipe
在编译过程的不同阶段间使用管道而非临时文件进行通信.这个选项在某些系统上无法工作,因为那些系统的汇编器不能从管道读取数据. GNU的汇编器没有这个问题.
语言选项(LANGUAGE OPTIONS)
下列选项控制编译器能够接受的C "方言":
-ansi
支持符合ANSI标准的C程序.
这样就会关闭GNU C中某些不兼容ANSI C的特性,例如asm, inline和typeof关键字,以及诸如unix和vax这些表明当前系统类型的预定义宏.同时开启不受欢迎和极少使用的ANSI trigraph特性,以及禁止$'成为标识符的一部分. 尽管使用了-ansi'选项,下面这些可选的关键字, asm, extension, inlinetypeof仍然有效.你当然不会把他们用在ANSI C程序中,但可以把他们放在头文件里,因为编译包含这些头文件的程序时,可能会指定-ansi'选项.另外一些预定义宏,如__unix__和__vax__,无论有没有使用-ansi'选项,始终有效.
使用-ansi'选项不会自动拒绝编译非ANSI程序,除非增加-pedantic'选项作为-ansi'选项的补充. 使用-ansi'选项的时候,预处理器会预定义一个STRICT_ANSI宏.有些头文件关注此宏,以避免声明某些函数,或者避免定义某些宏,这些函数和宏不被ANSI标准调用;这样就不会干扰在其他地方使用这些名字的程序了.
-fno-asm
不把asm, inline或typeof当作关键字,因此这些词可以用做标识符.用asm, inlinetypeof能够替代他们. -ansi' 隐含声明了-fno-asm'.
-fno-builtin
不接受不是两个下划线开头的内建函数(built-in function).目前受影响的函数有exit, abort, abs, alloca, cos, exit, fabs, labs, memcmp, memcpy, sin, sqrt, strcmp, strcpy,和strlen.
-ansi'选项能够阻止alloca和_exit成为内建函数. -fhosted 按宿主环境编译;他隐含声明了-fbuiltin'选项,而且警告不正确的main函数声明.
-ffreestanding
按独立环境编译;他隐含声明了-fno-builtin'选项,而且对main函数没有特别要求. (译注:宿主环境(hosted environment)下所有的标准库可用, main函数返回一个int值,典型例子是除了内核以外几乎所有的程序.对应的独立环境(freestanding environment)不存在标准库,程序入口也不一定是main,最明显的例子就是操作系统内核.详情参考gcc网站最近的资料) -fno-strict-prototype 对于没有参数的函数声明,例如int foo ();',按C风格处理---即不说明参数个数或类型. (仅针对C++).正常情况下,这样的函数foo在C++中意味着参数为空.
-trigraphs
支持ANSI C trigraphs. -ansi'选项隐含声明了-trigraphs'.
-traditional
试图支持传统C编译器的某些方面.详见GNU C手册,我们已经把细节清单从这里删除,这样当内容过时后,人们也不会埋怨我们.
除了一件事:对于C++程序(不是C), -traditional'选项带来一个附加效应,允许对this赋值.他和-fthis-is-variable'选项的效果一样.
-traditional-cpp
试图支持传统C预处理器的某些方面.特别是上面提到有关预处理器的内容,但是不包括-traditional'选项的其他效应. -fdollars-in-identifiers 允许在标识符(identifier)中使用$'字符(仅针对C++).你可以指定-fno-dollars-in-identifiers'选项显明禁止使用$'符. (GNU C++在某些目标系统缺省允许$'符,但不是所有系统.) -fenum-int-equiv 允许int类型到枚举类型(enumeration)的隐式转换(仅限于C++).正常情况下GNU C++允许从enum到int的转换,反之则不行. -fexternal-templates 为模板声明(template declaration)产生较小的代码(仅限于C++),方法是对于每个模板函数(template function),只在定义他们的地方生成一个副本.想要成功使用这个选项,你必须在所有使用模板的文件中,标记#pragma implementation' (定义)或#pragma interface' (声明). 当程序用-fexternal-templates'编译时,模板实例(template instantiation) 全部是外部类型.你必须让需要的实例在实现文件中出现.可以通过typedef实现这一点,他引用所需的每个实例.相对应的,如果编译时使用缺省选项-fno-external-templates',所有模板实例明确的设为内置. -fall-virtual 所有可能的成员函数默认为虚函数.所有的成员函数(除了构造子函数和new或delete 成员操作符)视为所在类的虚函数. 这不表明每次调用成员函数都将通过内部虚函数表.有些情况下,编译器能够判断出可以直接调用某个虚函数;这时就直接调用. -fcond-mismatch 允许条件表达式的第二和第三个参数的类型不匹配.这种表达式的值是void. -fthis-is-variable 允许对this赋值(仅对C++).合并用户自定义的自由存储管理机制到C++后,使可赋值的this'显得不合时宜.因此,默认情况下,类成员函数内部对this赋值是无效操作.然而为了向后兼容,你可以通过-fthis-is-variable'选项使这种操作有效. -funsigned-char 把char定义为无符号类型,如同unsigned char. 各种机器都有自己缺省的char类型.既可能是unsigned char也可能是signed char . 理想情况下,当依赖于数据的符号性时,一个可移植程序总是应该使用signed char或unsigned char.但是许多程序已经写成只用简单的char,并且期待这是有符号数(或者无符号数,具体情况取决于编写程序的目标机器).这个选项,和它的反义选项,使那样的程序工作在对应的默认值上. char的类型始终应该明确定义为signed char或unsigned char,即使它表现的和其中之一完全一样. -fsigned-char 把char定义为有符号类型,如同signed char. 这个选项等同于-fno-unsigned-char',他是the negative form of -funsigned-char'的相反选项.同样,-fno-signed-char'等价于-funsigned-char'. -fsigned-bitfields -funsigned-bitfields -fno-signed-bitfields -fno-unsigned-bitfields 如果没有明确声明signed'或unsigned'修饰符,这些选项用来定义有符号位域(bitfield)或无符号位域.缺省情况下,位域是有符号的,因为他们继承的基本整数类型,如int,是有符号数. 然而,如果指定了-traditional'选项,位域永远是无符号数.
-fwritable-strings
把字符串常量存储到可写数据段,而且不做特别对待.这是为了兼容一些老程序,他们假设字符串常量是可写的. -traditional'选项也有相同效果. 篡改字符串常量是一个非常糟糕的想法; ``常量''就应该是常量. [ GCC 1 || GCC 2 || GCC 3 || GCC 4 || GCC 5 ] GCC 2 Section: GNU Tools (1) Updated: 2003/12/05 预处理器选项(Preprocessor Option) 下列选项针对C预处理器,预处理器用在正式编译以前,对C 源文件进行某种处理. 如果指定了-E'选项, GCC只进行预处理工作.下面的某些选项必须和-E'选项一起才有意义,因为他们的输出结果不能用于编译. -include file 在处理常规输入文件之前,首先处理文件file,其结果是,文件file的内容先得到编译. 命令行上任何-D'和-U'选项永远在-include file'之前处理, 无论他们在命令行上的顺序如何.然而-include'和-imacros'选项按书写顺序处理.
-imacros file
在处理常规输入文件之前,首先处理文件file,但是忽略输出结果.由于丢弃了文件file的输出内容, -imacros file'选项的唯一效果就是使文件file中的宏定义生效, 可以用于其他输入文件.在处理-imacrosfile'选项之前,预处理器首先处理-D' 和-U'选项,并不在乎他们在命令行上的顺序.然而-include'和-imacros'选项按书写顺序处理.
-idirafter dir
把目录dir添加到第二包含路径中.如果某个头文件在主包含路径(用-I'添加的路径)中没有找到,预处理器就搜索第二包含路径. -iprefix prefix 指定prefix作为后续-iwithprefix'选项的前缀.
-iwithprefix dir
把目录添加到第二包含路径中.目录名由prefix和dir合并而成,这里prefix被先前的-iprefix'选项指定. -nostdinc 不要在标准系统目录中寻找头文件.只搜索-I'选项指定的目录(以及当前目录,如果合适).
结合使用-nostdinc'和-I-'选项,你可以把包含文件搜索限制在显式指定的目录.
-nostdinc++
不要在C++专用标准目录中寻找头文件,但是仍然搜索其他标准目录. (当建立libg++'时使用这个选项.) -undef 不要预定义任何非标准宏. (包括系统结构标志). -E 仅运行C预处理器.预处理所有指定的C源文件,结果送往标准输出或指定的输出文件. -C 告诉预处理器不要丢弃注释.配合-E'选项使用.
-P
告诉预处理器不要产生#line'命令.配合-E'选项使用.
-M [ -MG ]
告诉预处理器输出一个适合make的规则,用于描述各目标文件的依赖关系.对于每个源文件,预处理器输出一个make规则,该规则的目标项(target)是源文件对应的目标文件名,依赖项(dependency)是源文件中#include引用的所有文件.生成的规 则可以是单行,但如果太长,就用'-换行符续成多行.规则显示在标准输出,不产生预处理过的C程序.
-M'隐含了-E'选项.
-MG'要求把缺失的头文件按存在对待,并且假定他们和源程序文件在同一目录下.必须和-M'选项一起用.
-MM [ -MG ]
-M'选项类似,但是输出结果仅涉及用户头文件,象这样#include file"'.忽略系统头文件如#include <file>'. -MD 和-M'选项类似,但是把依赖信息输出在文件中,文件名通过把输出文件名末尾的.o'替换为.d'产生.同时继续指定的编译工作----MD'不象-M'那样阻止正常的编译任务.
Mach的实用工具md'能够合并.d'文件,产生适用于make'命令的单一的依赖文件. -MMD 和-MD'选项类似,但是输出结果仅涉及用户头文件,忽略系统头文件.
-H
除了其他普通的操作, GCC显示引用过的头文件名.
-Aquestion(answer)
如果预处理器做条件测试,如#if #question(answer)',该选项可以断言(Assert) question的答案是answer. -A-'关闭一般用于描述目标机的标准断言. -Dmacro 定义宏macro,宏的内容定义为字符串1'.
-Dmacro=defn
定义宏macro的内容为defn.命令行上所有的-D'选项在-U'选项之前处理.
-Umacro
取消宏macro. -U'选项在所有的-D'选项之后处理,但是优先于任何-include'或-imacros'选项.
-dM
告诉预处理器输出有效的宏定义列表(预处理结束时仍然有效的宏定义).该选项需结合-E'选项使用. -dD 告诉预处理器把所有的宏定义传递到输出端,按照出现的顺序显示. -dN 和-dD'选项类似,但是忽略宏的参量或内容.只在输出端显示#define name. 汇编器选项(ASSEMBLER OPTION) -Wa,option 把选项option传递给汇编器.如果option含有逗号,就在逗号处分割成多个选项. 连接器选项(LINKER OPTION) 下面的选项用于编译器连接目标文件,输出可执行文件的时候.如果编译器不进行连接,他们就毫无意义. object-file-name 如果某些文件没有特别明确的后缀a special recognized suffix, GCC就认为他们是目标文件或库文件. (根据文件内容,连接器能够区分目标文件和库文件).如果GCC执行连接操作,这些目标文件将成为连接器的输入文件. -llibrary 连接名为library的库文件. 连接器在标准搜索目录中寻找这个库文件,库文件的真正名字是liblibrary.a'.连接器会当做文件名得到准确说明一样引用这个文件.
搜索目录除了一些系统标准目录外,还包括用户以-L'选项指定的路径. 一般说来用这个方法找到的文件是库文件---即由目标文件组成的归档文件(archive file).连接器处理归档文件的方法是:扫描归档文件,寻找某些成员,这些成员的符号目前已被引用,不过还没有被定义.但是,如果连接器找到普通的目标文件,而不是库文件,就把这个目标文件按平常方式连接进来.指定-l'选项和指定文件名的唯一区别是, -l选项用lib'和.a'把library包裹起来,而且搜索一些目录. -lobjc 这个-l选项的特殊形式用于连接Objective C程序. -nostartfiles 不连接系统标准启动文件,而标准库文件仍然正常使用. -nostdlib 不连接系统标准启动文件和标准库文件.只把指定的文件传递给连接器. -static 在支持动态连接(dynamic linking)的系统上,阻止连接共享库.该选项在其他系统上无效. -shared 生成一个共享目标文件,他可以和其他目标文件连接产生可执行文件.只有部分系统支持该选项. -symbolic 建立共享目标文件的时候,把引用绑定到全局符号上.对所有无法解析的引用作出警告(除非用连接编辑选项-Xlinker -z -Xlinker defs'取代).只有部分系统支持该选项.
-Xlinker option
把选项option传递给连接器.可以用他传递系统特定的连接选项, GNU CC无法识别这些选项.
如果需要传递携带参数的选项,你必须使用两次-Xlinker',一次传递选项,另一次传递他的参数. 例如,如果传递-assert definitions',你必须写成-Xlinker -assert -Xlinker definitions',而不能写成-Xlinker "-assert definitions"',因为这样会把整个字符串当做一个参数传递,显然这不是连接器期待的.
-Wl,option
把选项option传递给连接器.如果option中含有逗号,就在逗号处分割成多个选项.
-u symbol
使连接器认为取消了symbol的符号定义,从而连接库模块以取得定义.你可以使用多个-u'选项,各自跟上不同的符号,使得连接器调入附加的库模块. 目录选项(DIRECTORY OPTION) 下列选项指定搜索路径,用于查找头文件,库文件,或编译器的某些成员: -Idir 在头文件的搜索路径列表中添加dir 目录. -I- 任何在-I-'前面用-I'选项指定的搜索路径只适用于#include "file"'这种情况;他们不能用来搜索#include <file>'包含的头文件. 如果用-I'选项指定的搜索路径位于-I-'选项后面,就可以在这些路径中搜索所有的#include'指令. (一般说来-I选项就是这么用的.)
还有, -I-'选项能够阻止当前目录(存放当前输入文件的地方)成为搜索#include "file"'的第一选择.没有办法克服-I-'选项的这个效应.你可以指定-I.'搜索那个目录,它在调用编译器时是当前目录.这和预处理器的默认行为不完全一样,但是结果通常令人满意.
-I-'不影响使用系统标准目录,因此,-I-'和-nostdinc'是不同的选项. -Ldir 在-l'选项的搜索路径列表中添加dir目录.
-Bprefix
这个选项指出在何处寻找可执行文件,库文件,以及编译器自己的数据文件.
编译器驱动程序需要执行某些下面的子程序: cpp',cc1' (或C++的cc1plus'),as'和ld'.他把prefix当作欲执行的程序的前缀,既可以包括也可以不包括machine/version/'.
对于要运行的子程序,编译器驱动程序首先试着加上-B'前缀(如果存在).如果没有找到文件,或没有指定-B'选项,编译器接着会试验两个标准前缀/usr/lib/gcc/'和/usr/local/lib/gcc-lib/'.如果仍然没能够找到所需文件,编译器就在PATH'环境变量指定的路径中寻找没加任何前缀的文件名. 如果有需要,运行时(run-time)支持文件libgcc.a'也在-B'前缀的搜索范围之内. 如果这里没有找到,就在上面提到的两个标准前缀中寻找,仅此而已.如果上述方法没有找到这个文件,就不连接他了.多数情况的多数机器上,libgcc.a'并非必不可少.
你可以通过环境变量GCC_EXEC_PREFIX获得近似的效果;如果定义了这个变量,其值就和上面说的一样用做前缀.如果同时指定了-B'选项和GCC_EXEC_PREFIX变量,编译器首先使用-B'选项,然后才尝试环境变量值.
警告选项(WARNING OPTION)
警告是针对程序结构的诊断信息,程序不一定有错误,而是存在风险,或者可能存在错误.
下列选项控制GNU CC产生的警告的数量和类型:
-fsyntax-only
检查程序中的语法错误,但是不产生输出信息.
-w
禁止所有警告信息.
-Wno-import
禁止所有关于#import的警告信息.
-pedantic
打开完全服从ANSI C标准所需的全部警告诊断;拒绝接受采用了被禁止的语法扩展的程序.
无论有没有这个选项,符合ANSI C标准的程序应该能够被正确编译(虽然极少数程序需要-ansi' 选项).然而,如果没有这个选项,某些GNU扩展和传统C特性也得到支持.使用这个选项可以拒绝这些程序.没有理由使用这个选项,他存在只是为了满足一些书呆子(pedant). 对于替选关键字(他们以
_'开始和结束) -pedantic'不会产生警告信息. Pedantic 也不警告跟在__extension__后面的表达式.不过只应该在系统头文件中使用这种转义措施,应用程序最好避免. -pedantic-errors 该选项和-pedantic'类似,但是显示错误而不是警告.
-W
对下列事件显示额外的警告信息:

非易变自动变量(nonvolatile automatic variable)可能在调用longjmp时发生改变. 这些警告仅在优化编译时发生.
编译器只知道对setjmp的调用,他不可能知道会在哪里调用longjmp,事实上一个信号处理例程可以在程序的任何地点调用他.其结果是,即使程序没有问题,你也可能会得到警告,因为无法在可能出现问题的地方调用longjmp.

既可以返回值,也可以不返回值的函数. (缺少结尾的函数体被看作不返回函数值)例如,下面的函数将导致这种警告:
foo (a)
{
if (a > 0)
return a;
}
由于GNU CC不知道某些函数永不返回(含有abort和longjmp),因此有可能出现虚假警告.

表达式语句或逗号表达式的左侧没有产生作用(side effect).如果要防止这种警告,应该把未使用的表达式强制转换为void类型.例如,这样的表达式x[i,j]'会导致警告,而x[(void)i,j]'就不会.

无符号数用>'或<='和零做比较.
-Wimplicit-int
警告没有指定类型的声明.
-Wimplicit-function-declaration
警告在声明之前就使用的函数.
-Wimplicit
同-Wimplicit-int和-Wimplicit-function-declaration.
-Wmain
如果把main函数声明或定义成奇怪的类型,编译器就发出警告.典型情况下,这个函数用于外部连接, 返回int数值,不需要参数,或指定两个参数.
-Wreturn-type
如果函数定义了返回类型,而默认类型是int型,编译器就发出警告.同时警告那些不带返回值的return语句,如果他们所属的函数并非void类型.
-Wunused
如果某个局部变量除了声明就没再使用,或者声明了静态函数但是没有定义,或者某条语句的运算结果显然没有使用, 编译器就发出警告.
-Wswitch
如果某条switch语句的参数属于枚举类型,但是没有对应的case语句使用枚举元素,编译器就发出警告. ( default语句的出现能够防止这个警告.)超出枚举范围的case语句同样会导致这个警告.
-Wcomment
如果注释起始序列/*'出现在注释中,编译器就发出警告. -Wtrigraphs 警告任何出现的trigraph (假设允许使用他们). -Wformat 检查对printf和scanf等函数的调用,确认各个参数类型和格式串中的一致. -Wchar-subscripts 警告类型是char的数组下标.这是常见错误,程序员经常忘记在某些机器上char有符号 .-Wuninitialized 在初始化之前就使用自动变量. 这些警告只可能做优化编译时出现,因为他们需要数据流信息,只有做优化的时候才估算数据流信息.如果不指定-O'选项,就不会出现这些警告.
这些警告仅针对等候分配寄存器的变量.因此不会发生在声明为volatile的变量上面,不会发生在已经取得地址的变量,或长度不等于1, 2, 4, 8字节的变量.同样也不会发生在结构,联合或数组上面,即使他们在寄存器中.
注意,如果某个变量只计算了一个从未使用过的值,这里可能不会警告.因为在显示警告之前,这样的计算已经被数据流分析删除了.
这些警告作为可选项是因为GNU CC还没有智能到判别所有的情况,知道有些看上去错误的代码其实是正确的.下面是一个这样的例子:
{
int x;
switch (y)
{
case 1: x = 1;
break;
case 2: x = 4;
break;
case 3: x = 5;
}
foo (x);
}
如果y始终是1, 2或3,那么x总会被初始化,但是GNU CC不知道这一点.下面是另一个普遍案例:
{
int save_y;
if (change_y) save_y = y, y = new_y;
...
if (change_y) y = save_y;
}
这里没有错误,因为只有设置了save_y才使用他.
把所有不返回的函数定义为volatile可以避免某些似是而非的警告.
-Wparentheses
在某些情况下如果忽略了括号,编译器就发出警告.
-Wtemplate-debugging
当在C++程序中使用template的时候,如果调试(debugging)没有完全生效,编译器就发出警告. (仅用于C++).
-Wall
结合所有上述的-W'选项.通常我们建议避免这些被警告的用法,我们相信,恰当结合宏的使用能够轻易避免这些用法。 剩下的-W...'选项不包括在`-Wall'中,因为我们认为在必要情况下,这些被编译器警告的程序结构,可以合理的用在"干净的"程序中.
-Wtraditional
如果某些程序结构在传统C中的表现和ANSI C不同,编译器就发出警告.

宏参出现在宏体的字符串常量内部.传统C会替换宏参,而ANSI C则视其为常量的一部分.

某个函数在块(block)中声明为外部,但在块结束后才调用.

switch语句的操作数类型是long.
-Wshadow
一旦某个局部变量屏蔽了另一个局部变量,编译器就发出警告.
-Wid-clash-len
一旦两个确定的标识符具有相同的前len个字符,编译器就发出警告.他可以协助你开发一些将要在某些过时的,危害大脑的编译器上编译的程序.
-Wpointer-arith
任何语句如果依赖于函数类型的大小(size)或者void类型的大小,编译器就发出警告. GNU C为了便于计算void *指针和函数指针,就把这些类型的大小定义为1.
-Wcast-qual
一旦某个指针强制类型转换以便移除类型修饰符时,编译器就发出警告.例如,如果把const char * 强制转换为普通的char *时,警告就会出现.
-Wcast-align
一旦某个指针类型强制转换时,导致目标所需的地址对齐(alignment)增加,编译器就发出警告.例如,某些机器上只能在2或4字节边界上访问整数,如果在这种机型上把char *强制转换成int *类型, 编译器就发出警告.
-Wwrite-strings
规定字符串常量的类型是const char[length],因此,把这样的地址复制给non-const char *指针将产生警告.这些警告能够帮助你在编译期间发现企图写入字符串常量的代码,但是你必须非常仔细的在声明和原形中使用const,否则他们只能带来麻烦;所以我们没有让-Wall'提供这些警告. -Wconversion 如果某函数原形导致的类型转换和无函数原形时的类型转换不同,编译器就发出警告.这里包括定点数和浮点数的互相转换,改变定点数的宽度或符号,除非他们和缺省声明motion)相同. (default pro-Waggregate-return 如果定义或调用了返回结构或联合的函数,编译器就发出警告. (从语言角度你可以返回一个数组,然而同样会导致警告.) -Wstrict-prototypes 如果函数的声明或定义没有指出参数类型,编译器就发出警告. (如果函数的前向引用说明指出了参数类型,则允许后面使用旧式风格的函数定义,而不会产生警告.) -Wmissing-prototypes 如果没有预先声明函数原形就定义了全局函数,编译器就发出警告.即使函数定义自身提供了函数原形也会产生这个警告. 他的目的是检查没有在头文件中声明的全局函数. -Wmissing-declarations 如果没有预先声明就定义了全局函数,编译器就发出警告.即使函数定义自身提供了函数原形也会产生这个警告.这个选项的目的是检查没有在头文件中声明的全局函数. -Wredundant-decls 如果在同一个可见域某定义多次声明,编译器就发出警告,即使这些重复声明有效并且毫无差别 .-Wnested-externs 如果某extern声明出现在函数内部,编译器就发出警告. -Wenum-clash 对于不同枚举类型之间的转换发出警告(仅适用于C++). -Wlong-long 如果使用了long long 类型就发出警告.该警告是缺省项.使用-Wno-long-long' 选项能够防止这个警告. -Wlong-long'和-Wno-long-long'仅在-pedantic'之下才起作用. -Woverloaded-virtual (仅适用于C++.)在继承类中,虚函数的定义必须匹配虚函数在基类中声明的类型特征(type signature).当继承类声明了某个函数,它可能是个错误的尝试企图定义一个虚函数,使用这个选项能够产生警告:就是说,当某个函数和基类中的虚函数同名,但是类型特征不符合基类的任何虚函数,编译器将发出警告. -Winline 如果某函数不能内嵌(inline),无论是声明为inline或者是指定了-finline-functions 选项,编译器都将发出警告. -Werror 视警告为错误;出现任何警告即放弃编译. [ GCC 1 || GCC 2 || GCC 3 || GCC 4 || GCC 5 ] GCC 3 Section: GNU Tools (1) Updated: 2003/12/05 调试选项(DEBUGGING OPTION) GNU CC拥有许多特别选项,既可以调试用户的程序,也可以对GCC排错: -g 以操作系统的本地格式(stabs, COFF, XCOFF,或DWARF).产生调试信息. GDB能够使用这些调试信息. 在大多数使用stabs格式的系统上,-g'选项启动只有GDB才使用的额外调试信息;这些信息使GDB 调试效果更好,但是有可能导致其他调试器崩溃,或拒绝读入程序.如果你确定要控制是否生成额外的信息, 使用-gstabs+',-gstabs', -gxcoff+',-gxcoff', -gdwarf+',或-gdwarf' (见下文).
和大多数C编译器不同, GNU CC允许结合使用-g'和-O'选项.优化的代码偶尔制造一些惊异的结果:某些声明过的变量根本不存在;控制流程直接跑到没有预料到的地方;某些语句因为计算结果是常量或已经确定而没有执行;某些语句在其他地方执行,因为他们被移到循环外面了.
然而它证明了调试优化的输出是可能的.对可能含有错误的程序使用优化器是合理的.
如果GNU CC支持输出多种调试信息,下面的选项则非常有用.
-ggdb
以本地格式(如果支持)输出调试信息,尽可能包括GDB扩展.
-gstabs
以stabs格式(如果支持)输出调试信息,不包括GDB扩展.这是大多数BSD系统上DBX使用的格式.
-gstabs+
以stabs格式(如果支持)输出调试信息,使用只有GNU调试器(GDB)理解的GNU扩展.使用这些扩展有可能导致其他调试器崩溃或拒绝读入程序.
-gcoff
以COFF格式(如果支持)输出调试信息.这是在System V第四版以前的大多数System V系统上SDB使用的格式.
-gxcoff
以XCOFF格式(如果支持)输出调试信息.这是IBM RS/6000系统上DBX调试器使用的格式.
-gxcoff+
以XCOFF格式(如果支持)输出调试信息,使用只有GNU调试器(GDB)理解的GNU扩展.使用这些扩展有可能导致其他调试器崩溃或拒绝读入程序.
-gdwarf
以DWARF格式(如果支持)输出调试信息.这是大多数System V第四版系统上SDB使用的格式.
-gdwarf+
以DWARF格式(如果支持)输出调试信息,使用只有GNU调试器(GDB)理解的GNU扩展.使用这些扩展有可能导致其他调试器崩溃或拒绝读入程序.
-glevel -ggdblevel -gstabslevel -gcofflevel -gxcofflevel
-gdwarflevel
请求生成调试信息,同时用level指出需要多少信息.默认的level值是2.
Level 1输出最少量的信息,仅够在不打算调试的程序段内backtrace.包括函数和外部变量的描述,但是没有局部变量和行号信息.
Level 3包含更多的信息,如程序中出现的所有宏定义.当使用-g3'选项的时候,某些调试器支持宏扩展. -p 产生额外代码,用于输出profile信息,供分析程序prof使用. -pg 产生额外代码,用于输出profile信息,供分析程序gprof使用. -a 产生额外代码,用于输出基本块(basic block)的profile信息,它记录各个基本块的执行次数,供诸如tcov此类的程序分析.但是注意,这个数据格式并非tcov期待的.最终GNU gprof 将处理这些数据. -ax 产生额外代码,用于从'bb.in'文件读取基本块的profile参数,把profile的结果写到'bb.out' 文件.bb.in'包含一张函数列表.一旦进入列表中的某个函数, profile操作就开始,离开最外层的函数后, profile操作就结束.以-'为前缀名的函数排除在profile操作之外.如果函数名不是唯一的,它可以写成/path/filename.d:functionname'来澄清. bb.out'将列出一些有效的文件名.这四个函数名具有特殊含义:bb_jumps'导致跳转(jump)频率写进bb.out'.bb_trace'导致基本块序列通过管道传到gzip',输出bbtrace.gz'文件. __bb_hidecall__'导致从跟踪(trace)中排除call 指令.bb_showret'导致在跟踪中包括返回指令.
-dletters
编译的时候,在letters指定的时刻做调试转储(dump).用于调试编译器.大多数转储的文件名通过源文件名添加字词获得(例如foo.c.rtl'或foo.c.jump').
-dM
预处理结束的时候转储所有的宏定义,不输出到文件.
-dN
预处理结束的时候转储所有的宏名.
-dD
预处理结束的时候转储所有的宏定义,同时进行正常输出.
-dy
语法分析(parse)的时候在标准错误转储调试信息.
-dr
RTL阶段后转储到file.rtl'. -dx 仅对函数生成RTL,而不是编译.通常和r'联用.
-dj
第一次跳转优化后转储到file.jump'. -ds CSE (包括有时候跟在CSE后面的跳转优化)后转储到file.cse'.
-dL
循环优化后转储到file.loop'. -dt 第二次CSE处理(包括有时候跟在CSE后面的跳转优化)后转储到file.cse2'.
-df
流程分析(flow analysis)后转储到file.flow'. -dc 指令组合(instruction combination)后转储到file.combine'.
-dS
第一次指令安排(instruction schedule)后转储到file.sched'. -dl 局部寄存器分配后转储到file.lreg'.
-dg
全局寄存器分配后转储到file.greg'. -dR 第二次指令安排(instruction schedule)后转储到file.sched2'.
-dJ
最后一次跳转优化后转储到file.jump2'. -dd 推迟分支调度(delayed branch scheduling)后转储到file.dbr'.
-dk
寄存器-堆栈转换后转储到file.stack'. -da 产生以上所有的转储. -dm 运行结束后,在标准错误显示内存使用统计. -dp 在汇编输出加注指明使用了哪些模式(pattern)及其替代模式. -fpretend-float 交叉编译的时候,假定目标机和宿主机使用同样的浮点格式.它导致输出错误的浮点常数,但是在目标机上运行的时候, 真实的指令序列有可能和GNU CC希望的一样. -save-temps 保存那些通常是``临时''的中间文件;置于当前目录下,并且根据源文件命名.因此,用-c -save-temps'选项编译foo.c '会生成 foo.cpp'和foo.s' 以及foo.o'文件.
-print-file-name=library
显示库文件library的全路径名,连接时会使用这个库---其他什么事情都不作.根据这个选项, GNU CC既不编译,也不连接,仅仅显示文件名.
-print-libgcc-file-name
和-print-file-name=libgcc.a'一样.
-print-prog-name=program 类似于-print-file-name',但是查找程序program如cpp'. 优化选项(OPTIMIZATION OPTION) 这些选项控制多种优化措施: -O -O1 优化.对于大函数,优化编译占用稍微多的时间和相当大的内存. 不使用-O'选项时,编译器的目标是减少编译的开销,使编译结果能够调试.语句是独立的:如果在两条语句之间用断点中止程序,你可以对任何变量重新赋值,或者在函数体内把程序计数器指到其他语句,以及从源程序中精确地获取你期待的结果.
不使用-O'选项时,只有声明了register的变量才分配使用寄存器.编译结果比不用-O'选项的PCC要略逊一筹.
使用了-O'选项,编译器会试图减少目标码的大小和执行时间. 如果指定了-O'选项, -fthread-jumps'和-fdefer-pop'选项将被打开.在有delay slot的机器上, -fdelayed-branch'选项将被打开.在即使没有帧指针(frame pointer)也支持调试的机器上,-fomit-frame-pointer'选项将被打开.某些机器上还可能会打开其他选项.
-O2
多优化一些.除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作.例如不进行循环展开(loop unrolling)和函数内嵌(inlining).和-O选项比较,这个选项既增加了编译时间,也提高了生成代码的运行效果.
-O3
优化的更多.除了打开-O2所做的一切,它还打开了-finline-functions选项.
-O0
不优化.
如果指定了多个-O选项,不管带不带数字,最后一个选项才是生效的选项.
诸如-fflag'此类的选项描述一些机器无关的开关.大多数开关具有肯定和否定两种格式;-ffoo'开关选项的否定格式应该是-fno-foo'.下面的列表只展示了一种格式---那个不是默认选项的格式.你可以通过去掉或添加no-'构造出另一种格式.
-ffloat-store
不要在寄存器中存放浮点变量.这样可以防止某些机器上不希望的过高精度,如68000的浮点寄存器(来自68881)保存的精度超过了double应该具有的精度.
对于大多数程序,过高精度只有好处.但是有些程序严格依赖于IEEE浮点数的定义.对这样的程序可以使用-ffloat-store'选项. -fmemoize-lookups -fsave-memoized 使用探索法(heuristic)进行更快的编译(仅对C++).默认情况下不使用探索法.由于探索法只对某些输入文件有效,其他程序的编译速度会变得更慢. 第一次编译器必须对成员函数(或对成员数据的引用)建立一个调用.它必须(1)判断出这个类是否实现了那个名字的成员函数; (2)决定调用哪个成员函数(涉及到推测需要做哪种类型转换); (3)检查成员函数对调用者是否可见.所有这些构成更慢的编译.一般情形,第二次对成员函数(或对成员数据的引用)建立的调用,必须再次经过相同长度的处理.这意味着象这样的代码 cout << "This " << p << " has " << n << " legs.\n"; 对整个三步骤要做六次遍历.通过使用软件缓存, ``命中''能够显著地减少这种代价.然而不幸的是,使用这种缓存必须实现其他机制,带来了它自己的开销.-fmemoize-lookups'选项打开软件缓存.
因为函数的正文环境不同,函数对成员和成员函数的访问权(可见性)也可能不同, g++可能需要刷新缓存. 使用-fmemoize-lookups'选项,每编译完一个函数就刷新缓存.而-fsave-memoized'选项也启用同样的缓存,但是当编译器发觉最后编译的函数的正文环境产生的访问权和下一个待编译的函数相同,编译器就保留缓存内容.这对某个类定义许多成员函数时非常有用:除了某些其他类的友函数,每个成员函数拥有和其他成员函数完全一样的访问权,因而无需刷新缓存.
-fno-default-inline
默认为不要把成员函数内嵌,因为它们定义在类的作用域内(仅C++).
-fno-defer-pop
一旦函数返回,参数就立即弹出.对于那些调用函数后必须弹出参数的机器,编译器一般情况下让几次函数调用的参数堆积在栈上,然后一次全部弹出.
-fforce-mem
做数学运算前把将要使用的内存操作数送入寄存器.通过把内存访问转换成潜在的公共子表达式,它可能产生较好的目标码. 如果它们不是公共子表达式,指令组合应该消除各自的寄存器载荷.我乐意倾听不同意见.
-fforce-addr
做数学运算前把将要使用的内存地址常数送入寄存器.它可能和-fforce-mem'一样产生较好的目标码我乐意倾听不同意见. .-fomit-frame-pointer 对于不需要帧指针(frame pointer)的函数,不要在寄存器中保存帧指针.这样能够避免保存,设置和恢复帧指针的指令;同时对许多函数提供一个额外的寄存器. 但是在大多数机器上将无法调试. 某些机器上,如Vax,这个选项无效,因为标准调用序列自动处理帧指针,通过假装不存在而不保存任何东西.机器描述宏FRAME_POINTER_REQUIRED控制目标机是否支持这个选项. -finline-functions 把所有简单的函数集成进调用者.编译器探索式地决定哪些函数足够简单,值得这种集成. 如果集成了所有给定函数的调用,而且函数声明为static,那么一般说来GCC有权不按汇编代码输出函数. -fcaller-saves 允许在寄存器里分配数值,但是这个方案通常受到各个函数调用的冲击,因此GCC生成额外的代码,在函数调用的前后保存和复原寄存器内容.仅当生成代码看上去优于反之结果时才实现这样的分配. 某些机器上该选项默认为允许,通常这些机器没有调用保护寄存器代替使用. -fkeep-inline-functions 即使集成了某个函数的所有调用,而且该函数声明为static,仍然输出这个函数一个独立的,运行时可调用的版本. -fno-function-cse 不要把函数地址存入寄存器;让调用固定函数的指令显式给出函数地址. 这个选项产生效率较低的目标码,但是如果不用这个选项,某些不寻常的hack,改变汇编器的输出,可能因优化而带来困惑. -fno-peephole 禁止任何机器相关的peephole优化. -ffast-math 这个选项出于速度优化,允许GCC违反某些ANSI或IEEE规则/规格.例如,它允许编译器假设sqrt 函数的参数是非负数. 这个选项不被任何-O'选项打开,因为对于严格依靠IEEE或ANSI规则/规格实现的数学函数,程序可能会产生错误的结果.
下列选项控制特定的优化. -O2'选项打开下面的大多数优化项,除了-funroll-loops'和-funroll-all-loops'项. 而-O'选项通常打开-fthread-jumps'和-fdelayed-branch' 优化项,但是特定的机器上的默认优化项有可能改变.
如果特别情况下非常需要``微调''优化,你可以使用下面的选项.
-fstrength-reduce
执行循环强度缩小(loop strength reduction)优化,并且消除重复变量.
-fthread-jumps
执行优化的地点是,如果某个跳转分支的目的地存在另一个条件比较,而且该条件比较包含在前一个比较语句之内,那么执行优化.根据条件是true或者false,前面那条分支重定向到第二条分支的目的地或者紧跟在第二条分支后面.
-funroll-loops
执行循环展开(loop unrolling)优化.仅对循环次数能够在编译时或运行时确定的循环实行
.-funroll-all-loops
执行循环展开(loop unrolling)优化.对所有循环实行.通常使程序运行的更慢.
-fcse-follow-jumps
在公共子表达式消元(common subexpression elimination)的时候,如果没有其他路径到达某个跳转的目的地,就扫过这条jump指令.例如,如果CSE遇到带有else从句的if语句,当条件测试为false时, CSE就跟在jump后面.
-fcse-skip-blocks
它类似于-fcse-follow-jumps'选项,但是CSE跟在条件跳转后面,条件跳转跳过了语句块(block).如果CSE遇到一条简单的if语句,不带else从句,-fcse-skip-blocks'选项将导致CSE跟在if产生的跳转后面.
-frerun-cse-after-loop
执行循环优化后重新进行公共子表达式消元.
,-felide-constructors
如果看上去合理就省略构造子(仅C++).根据这个选项,对于下面的代码, GNU C++直接从调用foo 初始化y,而无需通过临时变量:
A foo (); A y = foo ();
如果没有这个选项, GNU C++首先通过调用类型A 合适的构造子初始化y;然后把foo的结果赋给临时变量;最后,用临时变量替换y'的初始值. ANSI C++标准草案规定了默认行为(-fno-elide-constructors').如果程序的构造子存在副效应, -felide-constructors'选项能够使程序有不同的表现,因为可能忽略一些构造子的调用. -fexpensive-optimizations 执行一些相对开销较大的次要优化. -fdelayed-branch 如果对目标机支持这个功能,它试图重新排列指令,以便利用延迟分支(delayed branch)指令后面的指令空隙. -fschedule-insns 如果对目标机支持这个功能,它试图重新排列指令,以便消除因数据未绪造成的执行停顿.这可以帮助浮点运算或内存访问较慢的机器调取指令,允许其他指令先执行,直到调取指令或浮点运算完成. -fschedule-insns2 类似于-fschedule-insns'选项,但是在寄存器分配完成后,需要一个额外的指令调度过程.对于寄存器数目相对较少,而且取内存指令大于一个周期的机器,这个选项特别有用.
目标机选项(TARGET OPTION)
缺省情况下, GNU CC编译出本机类型的目标码.然而也可以把他安装成交叉编译器, 为其他机型编译程序.事实上,针对不同的目标机,可以同时安装GNU CC相应的配置.然后用-b'选项指定目标机种. 顺便提一下,新版本和旧版本的GNU CC可以共存.其中一个版本(可能是最新的那个)为缺省版本,但是有时候你希望使用其他版本. -b machine 参数machine指出编译的目标机种.这个选项用于安装为交叉编译器的GNU CC. 参数machine的值和配置GNU CC交叉编译器时设置的机器类型一样.例如,如果交叉编译器配置有configure i386v',意思是编译80386上的System V目标码,那么你可以通过-b i386v'运行交叉编译器. 如果没有指定-b'选项,通常指编译本机目标码.
-V version
参数version指出运行哪个版本的GNU CC.这个选项用于安装了多个版本的GCC.例如,如果version是`2.0',意味着运行GNU CC 2.0版.

Liunx PHP的GD库 添加 jpeg 文件的支持

一般源码安装添加的GD库 是不支持 jpeg 格式的图片的,只支持如下格式

GD Support enabled
GD Version bundled (2.0.34 compatible)
gif Read Support enabled
gif Create Support enabled
png Support enabled
libpng Version 1.2.49
WBMP Support enabled
XBM Support enabled
下面我们来 添加 jpeg 格式文件的支持
wget http://www.ijg.org/files/jpegsrc.v8b.tar.gz

tar -zxvf jpegsrc.v8b.tar.gz
cd jpeg-8b

./configure --prefix=/usr/local/jpeg --enable-shared --enable-static
make && make install

下面进入到 php 源码目录下 的 ext 下的 gd目录

进入gd 目录后执行 注意下面的 /usr/local/php/ 是你服务器 php的安装路径。我的是 这个路径就写成这样了

/usr/local/php/bin/phpize

./configure --with-php-config=/usr/local/php/bin/php-config --with-jpeg-dir=/usr/local/jpeg/

make && make install

执行完这些 系统就会提示你 gd.so 生成目录

在php.ini下 添加 gd.so 后 重启php 重启 应用服务器后就OK了

有些机器可能还不行,这样解决

yum install libjpeg-devel freetype-devel libpng-devel
make clean后重新./configure
make&make install

查看phpinfo OK了

PHP 对 png 图像进行缩放,支持透明背景

  <?php  function smart_resize_image( $file, $width = 0, $height = 0, $proportional = false, $output = 'file', $delete_original = true, $use_linux_commands = false )
        {
            if ( $height <= 0 && $width <= 0 ) {
                return false;
            }
            $info = getimagesize($file);
            $image = '';
      
            $final_width = 0;
            $final_height = 0;
            list($width_old, $height_old) = $info;
      
            if ($proportional) {
                if ($width == 0) $factor = $height/$height_old;
                elseif ($height == 0) $factor = $width/$width_old;
                else $factor = min ( $width / $width_old, $height / $height_old);  
                $final_width = round ($width_old * $factor);
                $final_height = round ($height_old * $factor);
      
            }
            else {       
                $final_width = ( $width <= 0 ) ? $width_old : $width;
                $final_height = ( $height <= 0 ) ? $height_old : $height;
            }
      
            switch ($info[2] ) {
                case IMAGETYPE_gif:
                    $image = imagecreatefromgif($file);
                break;
                case IMAGETYPE_JPEG:
                    $image = imagecreatefromjpeg($file);
                break;
                case IMAGETYPE_png:
                    $image = imagecreatefrompng($file);
                break;
                default:
                    return false;
            }
      
            $image_resized = imagecreatetruecolor( $final_width, $final_height );
      
            if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) {
                $trnprt_indx = imagecolortransparent($image);
                // If we have a specific transparent color
                if ($trnprt_indx >= 0) {
                    // Get the original image's transparent color's RGB values
                    $trnprt_color    = imagecolorsforindex($image, $trnprt_indx);
                    // Allocate the same color in the new image resource
                    $trnprt_indx    = imagecolorallocate($image_resized, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']);
                    // Completely fill the background of the new image with allocated color.
                    imagefill($image_resized, 0, 0, $trnprt_indx);
                    // Set the background color for new image to transparent
                    imagecolortransparent($image_resized, $trnprt_indx);
                }
                // Always make a transparent background color for PNGs that don't have one allocated already
                elseif ($info[2] == IMAGETYPE_PNG) {
                    // Turn off transparency blending (temporarily)
                    imagealphablending($image_resized, false);
                    // Create a new transparent color for image
                    $color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127);
      
                    // Completely fill the background of the new image with allocated color.
                    imagefill($image_resized, 0, 0, $color);
      
                    // Restore transparency blending
                    imagesavealpha($image_resized, true);
                }
            }
      
            imagecopyresampled($image_resized, $image, 0, 0, 0, 0, $final_width, $final_height, $width_old, $height_old);
      
            if ( $delete_original ) {
                if ( $use_linux_commands )
                    exec('rm '.$file);
                else
                    @unlink($file);
            }
      
            switch ( strtolower($output) ) {
                case 'browser':
                    $mime = image_type_to_mime_type($info[2]);
                    header("Content-type: $mime");
                    $output = NULL;
                break;
                case 'file':
                    $output = $file;
                break;
                case 'return':
                    return $image_resized;
                break;
                default:
                break;
            }
      
            switch ($info[2] ) {
                case IMAGETYPE_GIF:
                    imagegif($image_resized, $output);
                break;
                case IMAGETYPE_JPEG:
                    imagejpeg($image_resized, $output);
                break;
                case IMAGETYPE_PNG:
                    imagepng($image_resized, $output);
                break;
                default:
                    return false;
            }
      
            return true;
        }

生成图像缩略图(支持:JPEG,GIT,PNG,BMP)

<?php
class Thumb
{
 
    public function create($srcPath, $dstPath, $dstWidth, $dstHeight)
    {
        if (!file_exists($srcPath)) {
            return false;
        }
 
        @$srcSize = getimagesize($srcPath);
        if (empty($srcSize)) {
            return false;
        }
 
        $srcWith = intval($srcSize[0]);
        $srcHeight = intval($srcSize[1]);
 
        //如果原始图片的尺寸大于指定缩略图的尺寸,则生成缩略图,否则拷贝原始文件
        if ($srcWith <= $dstWidth && $srcHeight <= $dstHeight) {
            return copy($srcPath, $dstPath);
        }
 
        //读取原始图片资源
        @$srcImage = imagecreatefromjpeg($srcPath);
        if (empty($srcImage)) {
            @$srcImage = imagecreatefromgif($srcPath);
        }
        if (empty($srcImage)) {
            @$srcImage = imagecreatefrompng($srcPath);
        }
        if (empty($srcImage)) {
            @$srcImage = $this->_imageCreateFromBMP($srcPath);
        }
 
        if (empty($srcImage)) {
            return false;
        }
 
        //获取缩略图的尺寸,并据此生成新的图像
        $dstSize = $this->_getDstSize(
            $srcWith, $srcHeight, $dstWidth, $dstHeight
        );
 
        @$dstImage = imagecreatetruecolor(
            $dstSize['width'], $dstSize['height']
        );
 
        @imagecopyresampled(
            $dstImage, $srcImage , 0, 0, 0, 0,
            $dstSize['width'], $dstSize['height'],
            $srcWith, $srcHeight
        );
 
        return @imagepng($srcPath, $dstPath);
    }
 
    private function _imageCreateFromBMP($filePath)
    {
        $fileHandle = fopen($filePath, 'rb');
        if (empty($fileHandle)) {
            return false;
        }
 
        $file = unpack(
            'vfile_type/Vfile_size/Vreserved/Vbitmap_offset',
            fread($fileHandle, 14)
        );
 
        if ($file['file_type'] != 19778) {
            return false;
        }
 
        $bmp = unpack(
            'Vheader_size/Vwidth/Vheight/vplanes/'.
            'vbits_per_pixel/vcompression/Vsize_bitmap/'.
            'Vhoriz_resolution/Vvert_resolution/vcolors_used/Vcolors_important',
            fread($fileHandle, 40)
        );
        $bmp['colors'] = pow(2, $bmp['bits_per_pixel']);
        if ($bmp['size_bitmap'] == 0) {
            $bmp['size_bitmap'] = $file['file_size'] - $file['bitmap_offset'];
        }
        $bmp['bytes_per_pixel'] = $bmp['bits_per_pixel'] / 8;
        $bmp['bytes_per_pixel2'] = ceil($bmp['bytes_per_pixel']);
        $bmp['decal'] =  $bmp['width'] * $bmp['bytes_per_pixel'] / 4;
        $bmp['decal'] -= floor($bmp['width'] * $bmp['bytes_per_pixel'] / 4);
        $bmp['decal'] = 4 - (4 * $bmp['decal']);
        if ($bmp['decal'] == 4) {
            $bmp['decal'] = 0;
        }
 
        $palette = array();
        if ($bmp['colors'] < 16777216) {
            $palette = unpack(
                'V' . $bmp['colors'],
                fread($fileHandle, $bmp['colors'] * 4)
            );
        }
        $image = fread($fileHandle, $bmp['size_bitmap']);
        $vide = chr(0);
        $res = imagecreatetruecolor($bmp['width'], $bmp['height']);
        $p = 0;
 
        $y = $bmp['height'] - 1;
        while ($y >= 0) {
            $x = 0;
            while ($x < $bmp['width']) {
                if ($bmp['bits_per_pixel'] == 24) {
                    $color = unpack('V', substr($image, $p, 3) . $vide);
                } else if ($bmp['bits_per_pixel'] == 16) {
                    $color = unpack('n', substr($image, $p, 2));
                    $color[1] = $palette[$color[1]+1];
                } else if ($bmp['bits_per_pixel'] == 8) {
                    $color = unpack('n', $vide . substr ($image, $p, 1));
                    $color[1] = $palette[$color[1]+1];
                } else if ($bmp['bits_per_pixel'] ==4) {
                    $color = unpack('n', $vide . substr($image, floor($p), 1));
                    if (($p * 2) % 2 == 0) {
                        $color[1] = ($color[1] >> 4);
                    } else {
                        $color[1] = ($color[1] & 0x0F);
                    }
                    $color[1] = $palette[$color[1] + 1];
                } else if ($bmp['bits_per_pixel'] == 1) {
                    $color = unpack('n', $vide . substr($image, floor($p), 1));
                    switch (($p * 8) % 8) {
                        case  0:
                            $color[1] = ($color[1] >> 7);
                            break;
                        case  1:
                            $color[1] = ($color[1] & 0x40) >> 6;
                            break;
                        case  2:
                            $color[1] = ($color[1] & 0x20) >> 5;
                            break;
                        case  3:
                            $color[1] = ($color[1] & 0x10) >> 4;
                            break;
                        case  4:
                            $color[1] = ($color[1] & 0x8) >> 3;
                            break;
                        case  5:
                            $color[1] = ($color[1] & 0x4) >> 2;
                            break;
                        case  6:
                            $color[1] = ($color[1] & 0x2) >> 1;
                            break;
                        case  7:
                            $color[1] = ($color[1] & 0x1);
                            break;
                     }
                     $color[1] = $palette[$color[1] + 1];
                } else {
                    return false;
                }
                imagesetpixel($res, $x, $y, $color[1]);
                $x++;
                $p += $bmp['bytes_per_pixel'];
            }
            $y--;
            $p += $bmp['decal'];
        }
        fclose($fileHandle);
        return $res;
    }
 
    private function _getDstSize($srcWith, $srcHeight, $dstWidth, $dstHeight)
    {
        $size = array('width' => $srcWith, 'height' => $srcHeight);
        if ($dstWidth > 0 && $dstHeight > 0) {
            if ($srcWith > 0 && $srcHeight > 0) {
                if ($srcWith / $srcHeight >= $dstWidth / $dstHeight) {
                    if ($srcWith > $dstWidth) {
                        $size['width']  = $dstWidth;
                        $size['height'] = $srcHeight * $dstWidth / $srcWith;
                    }
                } else {
                    if ($srcHeight > $dstHeight) {
                        $size['width']  = $srcWith * $dstHeight / $srcHeight;
                        $size['height'] = $dstHeight;
                    }
                }
            }
        }
        return $size;
    }
}