进程空间概要分析
问题
execve(...)
的参数分别是什么?有什么意义?
int create_process(char *path, char *args[])
{
int ret = fork();
if (ret == 0) {
execve(path, args, NULL);
}
return ret;
}
- execve 的本质是系统调用而非函数!!
main 函数(默认进程入口)
int main(int argc, char *argv[])
agrc - 命令行参数个数
argv - 命令行参数数组
注意:启动参数和环境变量 【拷贝】 于父进程
进程空间概要
进程参数存储分析
mem.c
#include <stdio.h>
#include <stdlib.h>
static int g_init = 255;
static float g_uninit;
static void text()
{
}
int main(int argc, char *argv[])
{
static double s_init = 0.255;
static double s_uninit;
int i = 0;
int *p = malloc(4);
printf("argv[0] = %p\n", argv[0]);
printf("&i = %p\n", &i);
printf("p = %p\n", p);
printf("&g_uninit = %p\n", &g_uninit);
printf("&s_uninit = %p\n", &s_uninit);
printf("&g_init = %p\n", &g_init);
printf("&s_init = %p\n", &s_init);
printf("text = %p\n", text);
free(p);
return 0;
}
tiansong@tiansong:~/Desktop/linux$ ./mem.out
argv[0] = 0x7fff7e27210c
&i = 0x7fff7e270c0c
p = 0x55c17314d2a0
&g_uninit = 0x55c1717eb028
&s_uninit = 0x55c1717eb030
&g_init = 0x55c1717eb010
&s_init = 0x55c1717eb018
text = 0x55c1717e81a9
下面程序输出什么?为什么?
child.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
sleep(3);
for (i=0; i<argc; ++i) {
printf("exec = %d %s\n", getpid(), argv[i]);
}
return 0;
}
parent.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define EXE "helloword.out"
int create_process(char *path, char *args[])
{
int ret = fork();
if (ret == 0) {
execve(path, args, NULL);
}
return ret;
}
void zero_str(char *s)
{
while (s && *s) *s++ = 0;
}
int main()
{
char path[] = EXE;
char arg1[] = "hello";
char arg2[] = "world";
char *args[] = {path, arg1, arg2, NULL};
printf("%d begin\n", getpid());
printf("%d child = %d\n", getpid(), create_process(EXE, args));
zero_str(path);
zero_str(arg1);
zero_str(arg2);
printf("%d path = %s\n", getpid(), path);
printf("%d arg1 = %s\n", getpid(), arg1);
printf("%d arg2 = %s\n", getpid(), arg2);
printf("%d end\n", getpid());
return 0;
}
tiansong@tiansong:~/Desktop/linux$ gcc parent.c -o parent.out
tiansong@tiansong:~/Desktop/linux$ gcc child.c -o helloword.out
tiansong@tiansong:~/Desktop/linux$ ./parent.out
4665 begin
4665 child = 4666
4665 path =
4665 arg1 =
4665 arg2 =
4665 end
tiansong@tiansong:~/Desktop/linux$ exec = 4666 helloword.out
exec = 4666 hello
exec = 4666 world
- 命令行参数,启动参数,进程参数本质相同
命令行参数规范
Linux 启动参数(命令行参数)规范
- 由选项,选项值,操作数组成
- 选项由短横线 (-) 开始,选项名必须是单个字母或数字字符
- 选项可以有选项值,选项与选项值之间可用空格分隔(
-o test ←→ -otest
) [推荐前者] - 如果多个选项均无选项值,可合而为一 (
-a-b-c ←→ -abc
) [推荐前者] - 既不是选项,也不能作为选项值的参数是操作数
- 第一次出现的双横线 (--) 用于结束所有选项,后续参数为操作数
gcc test.c -o test.out
操作数 选项 选项值
Linux 启动参数(命令行参数)解析
- 规则 :
if:s
(-i, -s, -f 选项值) - 示例:
Linux 启动参数(命令行参数)编程
#include <unistd.h>
extern char *optarg;
extern int optind, opterr, optopt;
int getopt(int argc, char *argv[], const char *optstring);
getopt(...)
从 argv[] 数组中获取启动参数,并根据 optstring 定义的规则进行解析getopt(...)
从 argc 和 argv 中获取下一个选项- 选项合法:返回值为选项字符,optarg 只想选项值字符串
- 选项不合法:返回字符 '?',optopt 保存当前选项字符(错误)
- 选项合法但缺少选项值:返回字符 ':',optopt 保存当权选项字符(错误)
- 默认情况下:
getopt(...)
对 argv 进行重排,所有操作数位于最后位置
命令行参数编程
main.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
int c = 0;
int iflg = 0;
int fflg = 0;
int sflg = 0;
char *fvalue = NULL;
while ((c = getopt(argc, argv, "f:is")) != -1) { // -i, -s, -f 合法,同时 -f 需要携带选项值
switch (c)
{
case 'f':
fflg = 1;
fvalue = optarg;
break;
case 'i':
iflg = 1;
break;
case 's':
sflg = 1;
break;
case '?':
printf("Unknow option: -%c\n", optopt);
break;
case ':':
printf("-%c missing option argmuent\n", optopt);
break;
case 1:
printf("inter: %s\n", optarg);
break;
default:
printf("ret = %d\n", c);
break;
}
}
printf("fflg = %d, fvalue = %s, iflg = %d, sflg = %d\n", fflg, fvalue, iflg, sflg);
for (i=optind; i<argc; ++i) { // option index, 每处理一个选项,下标 + 1
printf("parameter: %s\n", argv[i]);
}
return 0;
}
tiansong@tiansong:~/Desktop/linux$ gcc main.c -o main.out
tiansong@tiansong:~/Desktop/linux$ ./main.out
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
tiansong@tiansong:~/Desktop/linux$ ./main.out -i
fflg = 0, fvalue = (null), iflg = 1, sflg = 0
tiansong@tiansong:~/Desktop/linux$ ./main.out abc -f
./main.out: option requires an argument -- 'f' // 系统默认输出
Unknow option: -f
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
parameter: abc
tiansong@tiansong:~/Desktop/linux$ ./main.out -- abc -f
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
parameter: abc
parameter: -f
tiansong@tiansong:~/Desktop/linux$ ./main.out -v -m -n
./main.out: invalid option -- 'v'
Unknow option: -v
./main.out: invalid option -- 'm'
Unknow option: -m
./main.out: invalid option -- 'n'
Unknow option: -n
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
optstring 规则的扩展定义
起始字符可以是 :
:, +, -
或 省略- 省略 → 出现选项错误时,程序中通过
:
或?
进行处理并给出错误提示 :
→ 错误提示开关,程序中通过返回值:
或?
进行处理(无默认错误提示) 【关闭错误提示】+
→ 错误提示开关,遇见操作数是,返回 -1, 认为选项处理完毕(后续都是操作数) 【./demo.out a -v -n -m
, a 之后都为操作数,返回 -1】-
→ 不重排开关,遇见操作数时,返回 1 ,optarg 指向操作数字符串 【默认情况下:getopt(...) 对 argv 进行重排,所有操作数位于最后位置】- 组合 →
+:
or-:
- 省略 → 出现选项错误时,程序中通过
修改 main.c
, 关闭默认错误提示
while ((c = getopt(argc, argv, ":f:is")) != -1) {
tiansong@tiansong:~/Desktop/linux$ ./main.out -v -m -n
Unknow option: -v
Unknow option: -m
Unknow option: -n
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
修改 main.c
, 遇见操作数立即停止返回 -1
while ((c = getopt(argc, argv, "+:f:is")) != -1) {
tiansong@tiansong:~/Desktop/linux$ ./main.out -v abc -m -n
Unknow option: -v
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
parameter: abc
parameter: -m
parameter: -n
修改 main.c
, 不重排命令行参数,遇见操作数返回 1 ,后继续执行, optarg 指向操作数字符串
while ((c = getopt(argc, argv, "-:f:is")) != -1) {
tiansong@tiansong:~/Desktop/linux$ ./main.out -v abc -m -n
Unknow option: -v
inter: abc // 返回 1 后,继续执行
Unknow option: -m
Unknow option: -n
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
tiansong@tiansong:~/Desktop/linux$ ./main.out -v abc -m -n def
Unknow option: -v
inter: abc
Unknow option: -m
Unknow option: -n
inter: def
fflg = 0, fvalue = (null), iflg = 0, sflg = 0
问题:环境变量是什么?有什么意义?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。