系统编程(4)"/>
Linux系统编程(4)
分配数组
int *x, *y;
x = malloc(50*sizeof(int));
if(!x) {perror("malloc");return 1;
}y = calloc(50, sizeof(int));
if (!y) {perror("calloc");return 1;
}
calloc会将所申请的内存全部填充0,malloc则不会。
调整内存分配的大小
#include <stdlib.h>
void* realloc(void* ptr, size_t size);
创建匿名内存映射
#include <sys/mman.h>void * mmap(void* start, size_t length, int port, int flags, int fd, off_t offset);
int munmap(void* start, size_t length);
void* p;
p = mmap(NULL, // 此处无关紧要512*1024, // 512KBPROT_READ | PROT_WRITE, // 可供读取和写入MAP_ANONYMOUS | MAP_PRIVATE, // 匿名与私有-1, // fd 忽略0); // offset 忽略
if (p == MAP_FAILED)perror("mmap")
else
-- 第一个参数start设定为NULL,表示匿名映射的起始地址由内核自行决定,也可以指定非NULL的值,只要能够对齐页面,这样会导致移植性早到破坏。
-- 为了让映射可读可写,一般设定prot参数为PROT_READ | PROT_WRITE。
-- flags参数设定为MAP_ANONYMOUS | MAP_PRIVATE,
-- 当MAP_ANONYMOUS设定时,参数fd和offset会被忽略。
相比malloc之后再设置为memset,calloc会更加方便。
映射/dev/zero
void* p;
int fd;
// 打开/dev/zero以备读取和写入
fd = open("/dev/zero", O_RDWR);
if (fd < 0) {perror("open");return 1;
}
// /dev/zero 的【0, page size】映射
p = mmap(NULL, //此时无关紧要getpagesize(), // 映射一个页面PROT_READ | PROT_WRITE, // 可写可读MAP_PRIVATE, // 私有映射fd, // 映射 /dev/zero 0);if (p == MAP_FAILED) {perror("mmap");if (close(fd))perror("close");return -1;
}//关闭 /dev/zero
if (close(fd))perror("close");
将字符串复制到堆栈
alloca()常用于临时复制一个字符串
//想要复制 "song"
char* dup;dup = alloca(strlen(song)+1);
strcpy(dup, song);
//操作dup
return;
#define _GNU_SOURCE
#include <string.h>
char* strdupa(const char* s);
char* strndupa(const char* s, size_t n);
设定字节
#include <string.h>
void* memset(void* s, int c, size_t n);
比较字节
#include <string.h>
int memcmp(const void* s1, const void* s2, size_t n);
此函数会比较s1与s2的前n个字节,如果相等,返回0,如果s1<s2,返回<0的值,如果s1>s2,则返回.>0的值。
移动字节
#include <string.h>void* memmove(void* dst, const void* src, size_t n);
将src的前n个字节复制到dst,并返回dst.memmove()可以安全处理重叠区域。
#include <string.h>
void* memcpy(void* dst, const void* src, size_t n);
memcpy如同memmove,但是dst和src不可以重叠,如果重叠,则是未定义的。
#include <string.h>
void* memccpy(void* dst, const void* src, int c, size_t n);
memccpy()函数的行为如同memcpy(),但是如果此函数在src的前n个字节中发现了字节c,则停止复制,此函数会返回一个指针,指向dst中的c(如果找不到c,则指向NULL)之后的下一个字节。
最后使用mempcpy(),将数据复制到连续的内存位置。
#define _GNU_SOURCE
#include <string.h>void* mempcpy(void* dst, const void* src, size_t n);
mempcpy()函数的执行如同memcpy(),但是它会返回一个指针,指向复制的最后一个字节的下一个字节,如果有一组数据想要复制到连续的内存位置,这会很有用。
搜素字节
#include <string.h>
void* memchr(const void* s, int c, size_t n);#define _GNU_SOURCE
#include <string.h>void* memrchr(const void* s, int c, size_t n);
旋转字节
#define _GNU_SOURCE
#include <string.h>void* memfrob(void* s, size_t n);
信号列表
等待任何一个信号
下面的程序会停在pause()处,直到收到一个信号,才会从pause()返回。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>// SIGINT 处理程序
static void SIGINT_handler(int signo) {printf("Caught SIGINT!\n");exit(EXIT_SUCCESS);
}int main(int argc, char** argv) {/*** 将SIGINT_handler注册为我们用于处理SIGINT的信号处理程序*/if (signal(SIGINT, SIGINT_handler) == SIG_ERR) {fprintf(stderr, "Cannot handle SIGINT!\n");exit(EXIT_FAILURE);}for(;;) {pause();}return 0;
}
//编译:gcc -o test test.c
执行./test
然后输入Ctrl+C
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>// SIGINT 处理程序
static void SIGINT_handler(int signo) {if (signo == SIGINT) {printf("Caught SIGINT!\n");} else if (signo == SIGTERM) {printf("Caught SIGTERM!\n");} else {fprintf(stderr, "Unexpected signal!\n");exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);
}int main(int argc, char** argv) {/*** 将SIGINT_handler注册为我们用于处理SIGINT的信号处理程序*/if (signal(SIGINT, SIGINT_handler) == SIG_ERR) {fprintf(stderr, "Cannot handle SIGINT!\n");exit(EXIT_FAILURE);}/*** 将SIGINT_handler注册为我们用于处理SIGTERM的信号处理程序*/if (signal(SIGTERM, SIGINT_handler) == SIG_ERR) {fprintf(stderr, "Cannot handle SIGTERM!\n");exit(EXIT_FAILURE);}/*** SIGPROF 的行为重置为默认值*/if (signal(SIGPROF, SIG_DFL) == SIG_ERR) {fprintf(stderr, "Cannot handle SIGPROF!\n");exit(EXIT_FAILURE);}/*** 忽略SIGHUP*/if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {fprintf(stderr, "Cannot handle SIGHUP!\n");exit(EXIT_FAILURE);}for(;;) {pause();}return 0;
}
发送一个信号
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int signo);
给自己发送一个信号
#include <signal.h>
int raise(int signo);
给整个进程组传送一个信号
除了kill,可以使用
#include <signal.h>
int killpg(int pgrp, int signo);等效于
kill (-pgrp, signo);
保证可重入函数
信号集
#include <signal.h>
int sigemptyset(sigset_t * set);
int sigfillset(sigset_t* set);
int sigaddset(sigset_t* set, int signo);
int sigdelset(sigset_t* set, int signo);
int sigismember(const sigset_t* set, int signo);
linux还提供以下非标准的函数:
#define _GNU_SOURCE
#include <signal.h>int sigisemptyset(sigset_t* set);
int sigorset(sigset_t * dest, sigset_t* left, sigset_t* right);
int sigandset(sigset_t* dest, sigset_t* left, sigset_t* right);
时间的数据结构
#include <sys/time.h>
struct timeval {time_t tv_sec; //secondssusecondes_t tv_usec; //microsecondes
};#include <time.h>
struct timespec {time_t tv_sec; //secondslong tv_nsec; //nanosecondes
};
获取当前时间
#include <time.h>time_t time(time_t* t);time_t t;
printf("current time: %ld\n", (long)time(&t));
printf("the same value: %ld\n", (long)t);#include <sys/time.h>
int gettimeofday(struct timeval* tv, struct timezone* tz);
更多推荐
Linux系统编程(4)
发布评论