






















目录
知识点
limits.h 中提供的一些宏
和数值相关的一些定义:
CHAR_BIT, CHAR_MAX, CHAR_MIN, SCHAR_MAX, SCHAR_MIN, UCHAR_MAX, INT_MAX, INT_MIN, UINT_MAX, SHRT_MAX, SHRT_MIN, USHRT_MAX, LONG_MAX, LONG_MIN, ULONG_MAX, LLONG_MAX, LLONG_MIN, ULLONG_MAX, MB_LEN_MAX, // 在一个多字节字符常量中的最大字节数 FOPEN_MAX, // 允许同时打开的文件数 TMP_MAX, FILENAME_MAX, // 文件名长度
和系统运行相关的一些定义:
ARG_MAX -- exec 函数族的参数最大长度 ATEXIT_MAX -- 可用 atexit 函数登记的最大函数个数 CHILD_MAX -- 每个实际用户 ID 子进程最大个数 DELAYTIMER_MAX -- 定时器最大超限运行次数 HOST_NAME_MAX -- gethostname 返回的主机名长度 LOGIN_NAME_MAX -- 登录名最大长度 OPEN_MAX -- 赋予新建文件描述符的最大值 + 1 PAGESIZE -- 系统内存页大小(单位: 字节) RTSIG_MAX -- 为应用程序预留的事实信号的最大个数 SEM_NSEMS_MAX -- 一个进程可使用的信号量最大个数 SEM_VALUE_MAX -- 信号量最大值 SIGQUEUE_MAX -- 一个进程可排队信号的最大个数 STREAM_MAX -- 一个进程一词可打开的标准 I/O 流的最大个数 SYMLOOP_MAX -- 路径解析过程中可访问的符号链接数 TIMER_MAX -- 一个进程的定时器最大个数 TTY_NAME_MAX -- 终端设备名长度,其中包括 null 字节 TZNAME_MAX -- 时区的字节数
sysconf 中提供的一些参数
linux 系统中存在三种基础的配置, sysconf, pathconf 和 fpathconf。 这些函数可获取系统中在各个维度对进程做出的限制。通过 man 手册可以轻松的查阅。
POSIX.1 variables
We give the name of the variable, the name of the sysconf() argument used to inquire about its value, and a short description.
First, the POSIX.1 compatible values.
ARG_MAX - _SC_ARG_MAX
The maximum length of the arguments to the exec(3) family of functions. Must not be less than _POSIX_ARG_MAX (4096).
CHILD_MAX - _SC_CHILD_MAX
The maximum number of simultaneous processes per user ID. Must not be less than _POSIX_CHILD_MAX (25).
HOST_NAME_MAX - _SC_HOST_NAME_MAX
Maximum length of a hostname, not including the terminating null byte, as returned by gethostname(2). Must not be less than _POSIX_HOST_NAME_MAX (255).
LOGIN_NAME_MAX - _SC_LOGIN_NAME_MAX
Maximum length of a login name, including the terminating null byte. Must not be less than _POSIX_LOGIN_NAME_MAX (9).
NGROUPS_MAX - _SC_NGROUPS_MAX
Maximum number of supplementary group IDs.
clock ticks - _SC_CLK_TCK
The number of clock ticks per second. The corresponding variable is obsolete. It was of course called CLK_TCK. (Note: the macro CLOCKS_PER_SEC does not give information: it must equal 1000000.)
OPEN_MAX - _SC_OPEN_MAX
The maximum number of files that a process can have open at any time. Must not be less than _POSIX_OPEN_MAX (20).
PAGESIZE - _SC_PAGESIZE
Size of a page in bytes. Must not be less than 1.
PAGE_SIZE - _SC_PAGE_SIZE
A synonym for PAGESIZE/_SC_PAGESIZE. (Both PAGESIZE and PAGE_SIZE are specified in POSIX.)
RE_DUP_MAX - _SC_RE_DUP_MAX
The number of repeated occurrences of a BRE permitted by regexec(3) and regcomp(3). Must not be less than _POSIX2_RE_DUP_MAX (255).
STREAM_MAX - _SC_STREAM_MAX
The maximum number of streams that a process can have open at any time. If defined, it has the same value as the standard C macro FOPEN_MAX. Must not be less than _POSIX_STREAM_MAX (8).
SYMLOOP_MAX - _SC_SYMLOOP_MAX
The maximum number of symbolic links seen in a pathname before resolution returns ELOOP. Must not be less than _POSIX_SYMLOOP_MAX (8).
TTY_NAME_MAX - _SC_TTY_NAME_MAX
The maximum length of terminal device name, including the terminating null byte. Must not be less than _POSIX_TTY_NAME_MAX (9).
TZNAME_MAX - _SC_TZNAME_MAX
The maximum number of bytes in a timezone name. Must not be less than _POSIX_TZNAME_MAX (6).
_POSIX_VERSION - _SC_VERSION
indicates the year and month the POSIX.1 standard was approved in the format YYYYMML; the value 199009L indicates the Sept. 1990 revision.
POSIX.2 variables
Next, the POSIX.2 values, giving limits for utilities.
BC_BASE_MAX - _SC_BC_BASE_MAX
indicates the maximum obase value accepted by the bc(1) utility.
BC_DIM_MAX - _SC_BC_DIM_MAX
indicates the maximum value of elements permitted in an array by bc(1).
BC_SCALE_MAX - _SC_BC_SCALE_MAX
indicates the maximum scale value allowed by bc(1).
BC_STRING_MAX - _SC_BC_STRING_MAX
indicates the maximum length of a string accepted by bc(1).
COLL_WEIGHTS_MAX - _SC_COLL_WEIGHTS_MAX
indicates the maximum numbers of weights that can be assigned to an entry of the LC_COLLATE order keyword in the locale definition file.
EXPR_NEST_MAX - _SC_EXPR_NEST_MAX
is the maximum number of expressions which can be nested within parentheses by expr(1).
LINE_MAX - _SC_LINE_MAX
The maximum length of a utility's input line, either from standard input or from a file. This includes space for a trailing newline.
RE_DUP_MAX - _SC_RE_DUP_MAX
The maximum number of repeated occurrences of a regular expression when the interval notation \{m,n\} is used.
POSIX2_VERSION - _SC_2_VERSION
indicates the version of the POSIX.2 standard in the format of YYYYMML.
POSIX2_C_DEV - _SC_2_C_DEV
indicates whether the POSIX.2 C language development facilities are supported.
POSIX2_FORT_DEV - _SC_2_FORT_DEV
indicates whether the POSIX.2 FORTRAN development utilities are supported.
POSIX2_FORT_RUN - _SC_2_FORT_RUN
indicates whether the POSIX.2 FORTRAN run-time utilities are supported.
_POSIX2_LOCALEDEF - _SC_2_LOCALEDEF
indicates whether the POSIX.2 creation of locales via localedef(1) is supported.
POSIX2_SW_DEV - _SC_2_SW_DEV
indicates whether the POSIX.2 software development utilities option is supported.
These values also exist, but may not be standard.
- _SC_PHYS_PAGES
The number of pages of physical memory. Note that it is possible for the product of this value and the value of _SC_PAGESIZE to overflow.
- _SC_AVPHYS_PAGES
The number of currently available pages of physical memory.
- _SC_NPROCESSORS_CONF
The number of processors configured. See also get_nprocs_conf(3).
- _SC_NPROCESSORS_ONLN
The number of processors currently online (available). See also get_nprocs_conf(3).
基本系统数据类型
clock_t comp_t dev_t fd_set fpos_t gid_t ino_t mode_t nlink_t off_t pid_t pthread_t ptrdiff_t rlim_t sig_atomic_t sigset_t size_t ssize_t time_t uid_t wchar_t
7 进程环境
进程的启动
进程由内核 exec 调用,而进程的入口函数一般为 main 函数,但是也不一定,编译器一般在编译链接的时候有一个默认链接脚本,这个脚本给的入口函数就是 main 函数。
而启动进程所使用的参数和环境变量是从内核中取得的。
进程的退出
一般退出函数有以下几个:
// stdlib.h -- ISO void exit(int status); void _Exit(int status); // unistd.h-- POSIX.1 void _exit(int status);
如果想在进程推出的时候统一处理一些事情,可以使用 atexit 注册退出函数。 这些函数会在执行 exit 函数的时候执行。 先注册的函数会后执行,而且该功能并不会有去重处理,如果一个函数调用多次,那么这个函数也会执行多次。 一个进程至少可以注册 32 个终止处理函数,不同系统提供的数量不一样。 而且在所有的终止处理函数调用之后才会关闭所有打开的流。 注意,调用 _exit 和 _Exit 可能并不会触发终止处理函数。
// stdlib.h int atexit( void (*func)(void) );
以下是一些小知识点:
环境变量
每一个程序穷之后都会默认拥有一个全局变量 const char **environ , 该变量指向一组环境变量字符串,其中格式为 env_name=value 。 该字符串指针数组的最后一个值为 NULL , 因此你可以根据该特性判断字符串数组否遍历完。
操作环境变量有以下函数: 另外还可以通过 char *getenv(const char *name); 和 int putenv(char *string); 来访问特定的环境变量。
// stdlib.h int setenv(const char *name, const char *value, int overwrite); int unsetenv(const char *name); int putenv(char *string); char *getenv(const char *name); char *secure_getenv(const char *name); int clearenv(void);
程序空间布局
C 程序一般由以下几个部分组成:
一般可以通过 size 指令查看可执行文件的分配。
// chrome 浏览器的例子 size ~/bin/chrome.115.0.5790.102/opt/google/chrome/chrome text data bss dec hex filename 212567609 9669428 2722712 224959749 d689d05 /xxx/bin/chrome.115.0.5790.102/opt/google/chrome/chrome
另外在内存空间中可能还会存在其他类型的段,比如:包含符号表的段,包含调试信息的段以及包含动态共享库链接表的段 ...
存储空间分配
ISO 中定义了以下几种从堆空间分配内存空间的方法:
// stdlib.h void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void *reallocarray(void *ptr, size_t nmemb, size_t size); void free(void *ptr);
注意,realloc 后地址指针可能发生变化,因此,最好不要将 realloc 出来的地址空间的地址赋予其他指针,因为在 realloc 之后可能造成内存越界访问等未知错误。
在使用 xalloc 分配的空间一般是调用 sbrk 分配出来的,因为要管理这些从内核分配出来的存储区域,因此会在分配的内存区域存在一些管理数据。 如果在使用分配区域时发生越界写,可能会造成一些不可预知的问题(比如 SegmentFault, 或者对象的属性值被篡改等 ),但是因为这些错误一般不会马上显示出来,因此很难追查。 所以使用的时候需要格外小心。
为了方便检查内存泄露,越界访问,重复释放等问题,下面有些更加安全的库可以参考:
1. libmalloc
该库除了提供标准的一些内存分配回收函数外还提供了,用于存储空间配置的 mallopt, 和用于统计信息的 mallinfo
2. vamalloc
3. quick-fit
分配速度跟快,但是管理结构占用空间更大。
4. jemalloc
BSD 8.0 中使用的一个工具。
5. TCMalloc
google 开源, Google perftools 中的一个工具。
6. 函数 alloca
从当前函数栈上分配内存,在函数退出时释放。
但是某些平台因为进入函数之后无法变更栈的长度导致该函数不可用,因此在使用前应该先测试一下。
环境变量
通用的一些环境变量:
| 变量 | 描述 |
|---|---|
函数 setjump 和 longjump
goto 语句的局限性在于只能在一个函数内调用,而如果涉及到要跨函数进行 goto 的时候就要用到 setjump 和 longjump 函数了。
// setjmp.h int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val);
函数 getrlimit 和 setrlimit
该两个函数用于操作进程的一些限制。函数定义如下所示:
// sys/resource.h int getrlimit(int resource, struct rlimit *rlp); int setrlimit(int resource, const struct rlimit *rlp);
具体平台有哪些资源可以更改可以 man getrlimit 查看一下:
在使用该函数的时候需要注意以下三点:
一般可以操作的限制有如下这些:
| 变量 | 描述 |
|---|---|
进程
进程相关函数有下面这些:
// 获取进程的标识符有以下这些函数
// unistd.h
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void); -- 获取调用该进程的用户 ID
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
char *getlogin(void); -- 获取登录名
// unistd.h
// sys/types.h
extern char **environ;
int execl(const char *pathname, const char *arg, ... /* (char *) NULL */);
int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
int execle(const char *pathname, const char *arg, ... /*, (char *) NULL, char *const envp[] */);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
pid_t fork(void);
pid_t vfork(void); -- vfork 被该书认定为是有缺陷的,不应该在可移植的程序中包含他
void exit(int status);
int nice(int incr); -- 调整进程优先级,普通用户只能调低优先级,特权用户才能调高优先级,进程只能影响自己的优先级
int getpriority(int which, id_t who);
-- which 可以取三个值
---- PRIO_PROCESS 表示进程
---- PRIO_PGRP 表示进程组
---- PRIO_USER 表示用户 ID
int setpriority(int which, id_t who, int value);
// time.h
time_t time(time_t *_Nullable tloc); -- 获取 Unix 时间戳
// sys/time.h
-- RETURN
-- The return value may overflow the possible range of type clock_t.
-- On error, (clock_t) -1 is returned, and errno is set to indicate the error.
clock_t times(struct tms *buf);
struct tms {
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
};
基本介绍
进程一般都有一个非负整数的 ID, ID 是唯一的。 一般 0 号进程为内核调度进程,常被叫做交换进程 swapper, 该进程是内核一部分,并不执行任何磁盘上的程序,因此也称为系统进程。 ID 1 的进程一般为 init 进程。
现有的进程可以通过 fork 函数创建一个进程。 由 fork 创建的进程称为子进程, fork 函数会返回两次,区别是,子进程的返回值为 0, 而负进程会返回子进程的进程 id.
// unistd.h pid fork(void);
子进程继承父进程属性有以下这些:
父进程和子进程的具体区别如下:
Fork 与 vfor 的差异
vfork 创建子进程时并不会将父进程的地址空间完全复制到子进程中,因为 vfork 被认定为马上会调用 exec 或者 exit,于是也不会用到原有的地址空间。 这种优化的工作方式在某些 unix 系统中实现以提高工作效率,单如果子进程修改数据,进行函数调用,或者没有调用 exec 或者 exit 就返回会带来未知的结果(一般是不好的结果)。
Vfork 会保证子进程先运行,在他调用 exec 或者 exit 之后父进程才可能被调用运行。因此如果子进程中有依赖父进程的资源,那么会导致死锁。
Vfork 中如果修改了父进程的项目会直接影响原有父进程的值。
tips
gcc --static -o helloworld helloworld.c参考资料
原创文章,版权所有,转载请获得作者本人允许并注明出处
我是留白;我是留白;我是留白;(重要的事情说三遍)
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。