1 main函数的返回值

  • main函数是操作系统调用的函数
  • 操作系统总是将main函数的返回值作为程序的退出状态
  • main函数的返回值正常来说是0,如果是其他值,就是错误的状态。

2 main函数的参数

  • 程序执行的时候可以向main函数传递参数
  • main函数的参数是可变的,可以有多个参数。

那么如何向main函数传参数呢?在gcc编译器下是这样的:

2.1 main函数的参数的代码案例分析

  • 代码 33-3.c
#include <stdio.h>

int main(int argc, char* argv[], char* env[]){
    
    int i = 0;
    printf("============== Begin argv ==============\n");
    
    for(i=0; i<argc; i++){
        printf("%s\n", argv[i]);
    }
    
    printf("============== End argv ==============\n");
    
    printf("\n");
    printf("\n");
    printf("\n");
    
    printf("============== Begin env ==============\n");
    
    for(i=0; NULL!=env[i]; i++){
        printf("%s\n", env[i]);
    }
    
    printf("============== End env ==============\n");
    return 0;
}

首先我们要读懂上述代码。

  • 编译运行后,打印的环境变量有点多(gcc 4.4.5):
  • 运行结果为:

============== Begin argv ==============
./a.out
============== End argv ==============
============== Begin env ==============

ORBIT_SOCKETDIR=/tmp/orbit-delphi SSH_AGENT_PID=1922 TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=6c560f89cd4609726ff940b800000007-1551066414.182685-1366729942
WINDOWID=65011749 QTDIR=/usr/local/Trolltech
GNOME_KEYRING_CONTROL=/tmp/keyring-whMMzd
GTK_MODULES=canberra-gtk-module USER=delphi
LD_LIBRARY_PATH=/usr/local/Trolltech/Qt-4.7.4/lib:/usr/local/Trolltech/qtcreator-2.4.1/lib:
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:.tar=01;31:.tgz=01;31:.arj=01;31:.taz=01;31:.lzh=01;31:.lzma=01;31:.tlz=01;31:.txz=01;31:.zip=01;31:.z=01;31:.Z=01;31:.dz=01;31:.gz=01;31:.lz=01;31:.xz=01;31:.bz2=01;31:.bz=01;31:.tbz=01;31:.tbz2=01;31:.tz=01;31:.deb=01;31:.rpm=01;31:.jar=01;31:.rar=01;31:.ace=01;31:.zoo=01;31:.cpio=01;31:.7z=01;31:.rz=01;31:.jpg=01;35:.jpeg=01;35:.gif=01;35:.bmp=01;35:.pbm=01;35:.pgm=01;35:.ppm=01;35:.tga=01;35:.xbm=01;35:.xpm=01;35:.tif=01;35:.tiff=01;35:.png=01;35:.svg=01;35:.svgz=01;35:.mng=01;35:.pcx=01;35:.mov=01;35:.mpg=01;35:.mpeg=01;35:.m2v=01;35:.mkv=01;35:.ogm=01;35:.mp4=01;35:.m4v=01;35:.mp4v=01;35:.vob=01;35:.qt=01;35:.nuv=01;35:.wmv=01;35:.asf=01;35:.rm=01;35:.rmvb=01;35:.flc=01;35:.avi=01;35:.fli=01;35:.flv=01;35:.gl=01;35:.dl=01;35:.xcf=01;35:.xwd=01;35:.yuv=01;35:.cgm=01;35:.emf=01;35:.axv=01;35:.anx=01;35:.ogv=01;35:.ogx=01;35:.aac=00;36:.au=00;36:.flac=00;36:.mid=00;36:.midi=00;36:.mka=00;36:.mp3=00;36:.mpc=00;36:.ogg=00;36:.ra=00;36:.wav=00;36:.axa=00;36:.oga=00;36:.spx=00;36:.xspf=00;36:
SSH_AUTH_SOCK=/tmp/keyring-whMMzd/ssh
DEFAULTS_PATH=/usr/share/gconf/gnome.default.path
SESSION_MANAGER=local/delphi-vm:@/tmp/.ICE-unix/1891,unix/delphi-vm:/tmp/.ICE-unix/1891
USERNAME=delphi XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg
DESKTOP_SESSION=gnome LIBGL_ALWAYS_INDIRECT=1
PATH=/usr/local/Trolltech/Qt-4.7.4/bin:/usr/local/Trolltech/qtcreator-2.4.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
QT_IM_MODULE=xim PWD=/home/delphi/c XMODIFIERS=@im=ibus
GDM_KEYBOARD_LAYOUT=cn LANG=zh_CN.utf8 GNOME_KEYRING_PID=1872
MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path
GDM_LANG=zh_CN.utf8 GDMSESSION=gnome SHLVL=1 HOME=/home/delphi
LANGUAGE=zh_CN:zh GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=delphi
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-G9nxTNqahq,guid=1897c64e05f77bfe7d13058e00000f3e
XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/
LESSOPEN=| /usr/bin/lesspipe %s WINDOWPATH=7 DISPLAY=:0.0
GTK_IM_MODULE=ibus LESSCLOSE=/usr/bin/lesspipe %s %s
XAUTHORITY=/var/run/gdm/auth-for-delphi-ZsN9VV/database
COLORTERM=gnome-terminal
_=./a.out OLDPWD=/home/delphi
============== End env ==============

  • 虽然上面打印的消息比较多,但是结构很清晰。我们不过多的研究打印的消息,而是关心代码是怎么样写的。

3 main函数不一定是程序中第一个执行的函数

对于gcc编译器来说,它有一些属性关键字。可以利用这些属性关键字来构造先与main函数执行的函数,或者构造出main函数执行后执行的函数。

直接用代码说明问题会比较好:

  • 代码33-4.c
#include <stdio.h>

#ifndef __GNUC__ //判断是否是GNUC编译器
#define __attribute__(x) 
#endif

__attribute__((constructor))  //gcc属性关键字
void before_main()
{
    printf("%s\n",__FUNCTION__);
}

__attribute__((destructor))  //gcc属性关键字
void after_main()
{
    printf("%s\n",__FUNCTION__);
}

int main(){
    printf("%s\n","main");
    return 0;
}
  • 运行结果如下:

可以看出:

  • 使用gcc属性关键字可以构造先与main函数执行的函数
  • 也可以构造出在main函数执行之后执行的函数
  • 但是这种属性是依赖于编译器的,将上述代码拿到Windows的编译器运行可能就不对。所以一般不使用编译器的属性关键字
  • 上述代码的宏定义部分是判断当前是否是GNUC编译器。不是的话,就不支持该属性,直接顶一个一个空的宏__attribute__(x) ,它在后面的代码中也就没有意义了。

4 总结

  • main函数是操作系统调用的函数
  • 现代编译器支持在main函数前调用其他函数
  • 注意main函数的参数