为什么C++函数调用前必须声明
一、习惯性问题
刚从C++转到C开发的时候,觉得C里面一些函数调用不用声明函数原型,也不用定义,当时觉得很神奇。后来在C语言下开发久了,发现调用的函数没有声明导致编译错误,又觉得很神奇。看来很多东西习惯了就见鬼不怪了。
二、测试的代码
[tsecer@Harry GccTest]$ cat MustDec.c
int foo()
{
return NeitherDecNorDef(1);
}
[tsecer@Harry GccTest]$ gcc MustDec.c -c
[tsecer@Harry GccTest]$ g++ MustDec.c -c
MustDec.c: In function ‘int foo()’:
MustDec.c:3: error: ‘NeitherDecNorDef’ was not declared in this scope
[tsecer@Harry GccT_
三、为什么C++必须声明
因为C++支持函数过载。也就是说同样一个函数名,可以带不同的参数,从而形成不同的函数,它们可以并存并且不至于出现连接错误。这一切都要归功于C++名字粉碎的功劳,也就是mangling。
例如,在C++中,下面的代码可以编译通过
[tsecer@Harry gccg++]$ cat HappyCoexist.c
int foo(int arg)
{
return arg * arg;
}
int foo(short arg)
{
return arg / arg;
}
/*short foo(short arg)
{
return arg + arg;
}*/
可以看到,第一个和第二个函数的参数一个short,一个是int,但是可以共存。但是最后一个返回值和第二个不同却无法通过。
这一点因为很多函数调用的时候,可能并没有使用返回值,所以只是从函数返回值并不能确定调用处真正希望使用的是哪个函数,所以是一个二义语法。
看一下刚才生成的.o文件中的符号信息
[tsecer@Harry gccg++]$ nm HappyCoexist.o
00000000 T _Z3fooi
0000000c T _Z3foos
可见,里面并不是单单的foo那么简单,而是添加了参数信息到符号名中。所以对于最开始的测试例子
foo(1)
来说,如果没有声明,就不知道调用的是哪一个函数,从而在目标文件中也无法准确生成将要被重定位的符号名称。
四、另一个细节
gcc编译的时候,如果文件后缀为c,则认为是c文件;如果后缀为cxx或者cpp,则认为是c++文件,g++将所有文件当做c++文件。
[tsecer@Harry gccg++]$ cat HappyCoexist.cpp
int foo(int arg)
{
return arg * arg;
}
int foo(short arg)
{
return arg / arg;
}
/*short foo(short arg)
{
return arg + arg;
}*/
[tsecer@Harry gccg++]$ gcc HappyCoexist.cpp -c -v
Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC)
COLLECT_GCC_OPTIONS='-c' '-v' '-E' '-mtune=generic' '-march=i686'
/usr/libexec/gcc/i686-redhat-linux/4.4.2/cc1plus -E -quiet -v -D_GNU_SOURCE HappyCoexist.cpp -mtune=generic -march=i686
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../i686-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/i686-redhat-linux
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/backward
/usr/local/include
/usr/lib/gcc/i686-redhat-linux/4.4.2/include
/usr/include
End of search list.
COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-v' '-E' '-mtune=generic' '-march=i686'
Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC)
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16477.o' '-mtune=generic' '-march=i686'
/usr/libexec/gcc/i686-redhat-linux/4.4.2/cc1plus -fpreprocessed /home/tsecer/.ccache/HappyCoexi.tmp.Harry.16477.ii -quiet -dumpbase HappyCoexi.tmp.Harry.16477.ii -mtune=generic -march=i686 -auxbase-strip /home/tsecer/.ccache/tmp.hash.Harry.16477.o -version -o /tmp/ccaTdru8.s
GNU C++ (GCC) version 4.4.2 20091027 (Red Hat 4.4.2-7) (i686-redhat-linux)
compiled by GNU C version 4.4.2 20091027 (Red Hat 4.4.2-7), GMP version 4.3.1, MPFR version 2.4.1.
GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128396
Compiler executable checksum: 1654075adcfd832dfb7b0208272c8238
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16477.o' '-mtune=generic' '-march=i686'
as -V -Qy -o /home/tsecer/.ccache/tmp.hash.Harry.16477.o /tmp/ccaTdru8.s
GNU assembler version 2.19.51.0.14 (i686-redhat-linux) using BFD version version 2.19.51.0.14-34.fc12 20090722
COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16477.o' '-mtune=generic' '-march=i686'
[tsecer@Harry gccg++]$ g++ HappyCoexist.cpp -c -v
Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC)
COLLECT_GCC_OPTIONS='-c' '-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=i686'
/usr/libexec/gcc/i686-redhat-linux/4.4.2/cc1plus -E -quiet -v -D_GNU_SOURCE HappyCoexist.cpp -mtune=generic -march=i686
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../i686-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/i686-redhat-linux
/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/backward
/usr/local/include
/usr/lib/gcc/i686-redhat-linux/4.4.2/include
/usr/include
End of search list.
COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=i686'
Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC)
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16487.o' '-shared-libgcc' '-mtune=generic' '-march=i686'
/usr/libexec/gcc/i686-redhat-linux/4.4.2/cc1plus -fpreprocessed /home/tsecer/.ccache/HappyCoexi.tmp.Harry.16487.ii -quiet -dumpbase HappyCoexi.tmp.Harry.16487.ii -mtune=generic -march=i686 -auxbase-strip /home/tsecer/.ccache/tmp.hash.Harry.16487.o -version -o /tmp/ccsP2Dyc.s
GNU C++ (GCC) version 4.4.2 20091027 (Red Hat 4.4.2-7) (i686-redhat-linux)
compiled by GNU C version 4.4.2 20091027 (Red Hat 4.4.2-7), GMP version 4.3.1, MPFR version 2.4.1.
GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128396
Compiler executable checksum: 1654075adcfd832dfb7b0208272c8238
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16487.o' '-shared-libgcc' '-mtune=generic' '-march=i686'
as -V -Qy -o /home/tsecer/.ccache/tmp.hash.Harry.16487.o /tmp/ccsP2Dyc.s
GNU assembler version 2.19.51.0.14 (i686-redhat-linux) using BFD version version 2.19.51.0.14-34.fc12 20090722
COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/:/usr/libexec/gcc/i686-redhat-linux/4.4.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/:/usr/lib/gcc/i686-redhat-linux/4.4.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-v' '-o' '/home/tsecer/.ccache/tmp.hash.Harry.16487.o' '-shared-libgcc' '-mtune=generic' '-march=i686'
[tsecer@Harry gccg++]$