Stack-Based Allocations
要从栈中进行动态内存分配,请使用alloca()系统调用:
#include
void *alloca(size_t size);
不需要free。
int open_sysconf (const char *file, int flags, int mode) {
const char *etc = SYSCONF_DIR; /* "/etc/" */
char *name;
name = alloca (strlen (etc) + strlen (file) + 1);
strcpy (name, etc);
strcat (name, file);
return open (name, flags, mode);
}
int open_sysconf (const char *file, int flags, int mode) {
const char *etc = SYSCONF_DIR; /* "/etc/" */
char *name;
int fd;
name = malloc (strlen (etc) + strlen (file) + 1);
if (!name) {
perror ("malloc");
return −1;
}
strcpy (name, etc);
strcat (name, file);
fd = open (name, flags, mode);
free (name);
return fd;
}
如果您的程序必须保持可移植性,则应该避免alloca()。
在Linux上,alloca()是一个非常有用和利用不足的工具。
不要这么使用就行:
/* DO NOT DO THIS! */
ret = foo (x, alloca (10));
Duplicating String on the Stack
/* we want to duplicate 'song' */
char *dup;
dup = alloca (strlen (song) + 1);
strcpy (dup, song);
/* manipulate 'dup'... */
return; /* 'dup' is automatically freed */
#define _GNU_SOURCE
#include
char * strdupa (const char *s);
char * strndupa (const char *s, size_t n);
他们是一样的。
Variable-Length Arrays(VLA)
//典型用法
for (i = 0; i < n; ++i) {
char foo[i + 1];
/* use 'foo'... */
}
如果我们使用的是alloca()而不是VLA,则在函数返回之前不会释放内存。使用VLA确保在循环的每一次迭代中释放内存。因此,使用VLA消耗最多n个字节,而Alloca()则消耗n*(n+1)/2个字节。
int open_sysconf (const char *file, int flags, int mode) {
const char *etc; = SYSCONF_DIR; /* "/etc/" */
char name[strlen (etc) + strlen (file) + 1];
strcpy (name, etc);
strcat (name, file);
return open (name, flags, mode);
}
Choosing a Memory Allocation Mechansim
Manipulating Memory
Setting Bytes
#include
void * memset (void *s, int c, size_t n);
对memset()的调用将从s开始的n个字节设置为字节c并返回s。
#include
void bzero (void *s, size_t n);
请注意,bzero()(以及其他b接口)需要头
Comparing Bytes
#include
int memcmp (const void *s1, const void *s2, size_t n);
s1 = s2: return 0
s1 < s2: return <0
s1 > s2: return >0
#include
int bcmp (const void *s1, const void *s2, size_t n);
0的话相等,否则不相等。
比较两个结构体的话用memcmp是不安全的, 如下:
/* are two dinghies identical? (BROKEN) */
int compare_dinghies (struct dinghy *a, struct dinghy *b) {
return memcmp (a, b, sizeof (struct dinghy));
}
如果要比较结构体的话,我们应该比较结构体中的每个元素。
/* are two dinghies identical? */
int compare_dinghies (struct dinghy *a, struct dinghy *b) {
int ret;
if (a->nr_oars < b->nr_oars)
return −1;
if (a->nr_oars > b->nr_oars)
return 1;
ret = strcmp (a->boat_name, b->boat_name);
if (ret)
return ret;
/* and so on, for each member... */
}
Moving Bytes
#include
void * memmove (void *dst, const void *src, size_t n);
#include
void bcopy (const void *src, void *dst, size_t n);
上面这两个是是支持overlapping(dst的一部分在src中)
但是下面这个是不支持overlapping的,更块:
#include
void * memcpy (void *dst, const void *src, size_t n);
还有一种:
#include
void * memccpy (void *dst, const void *src, int c, size_t n);
与memcpy()相同,只是如果函数在src的前n个字节内找到字节c,则停止复制。调用返回在c之后指向dst中下一个字节的指针,如果没有找到c,则返回NULL。 .
最后,您可以使用mempcpy()来逐步遍历内存:
#define GNU_Source
#include
void*mempcpy(void*dst,const void*src,size_tn);
mempcpy()函数执行与memcpy()相同的操作。只不过它返回一个指针,指向上次复制的字节之后的下一个字节。如果要将一组数据复制到连续的内存位置,这是很有用的。但它并不是一个改进者 因为返回值仅仅是dst+n,这个函数是特定于GNU的。
Searching Bytes
#include
void * memchr (const void *s, int c, size_t n);
函数对s指向的n个字节的内存进行c字符扫描,调用返回第一个与c匹配的字节的指针,如果未找到c,则返回NULL。
#define _GNU_SOURCE
#include
void * memrchr (const void *s, int c, size_t n);
与memrchr()与memchr()是一样的,但是是逆序查找。
#define _GNU_SOURCE
#include
void * memmem (const void *haystack,
size_t haystacklen,
const void *needle,
size_t needlelen);
在haystack中查找needle,找到返回指针,找不到返回NULL。
Frobnicating Bytes
#define _GNU_SOURCE
#include
void * memfrob (void *s, size_t n);
对memfrob()的调用掩盖了从s开始的内存的前n个字节
再次调用将返回原来的值。
Locking Memory
Locking Part of an Address Space
#include
int mlock (const void *addr, size_t len);
成功返回0, 失败返回-1,并设置errno。
int ret;
/* lock 'secret' in memory */
ret = mlock (secret, strlen (secret));
if (ret)
perror ("mlock");
Locking All of an Address Space
#include
int mlockall (int flags);
flags参数列表:
- MCL_Current 将当前映射的所有页面(堆栈、数据段、映射文件等)锁定到进程的地址空间中。
- MCL_WORVERY,确保将来映射到地址空间的所有页也被锁定在内存中。
成功返回0,失败返回-1,并设置errno。
Unlocking Memory
#include
int munlock (const void *addr, size_t len);
int munlockall (void);
成功返回0, 失败返回-1,并且设置errno。
Locking Limits
拥有CAP_IPC_LOCK功能的进程可能会将任意数量的页面锁定到内存中。没有此功能的进程可能只锁定RLIMIT_MEMLOCK字节。
默认情况下,此资源限制为32KB-足够大,可锁定内存中的一个或两个密码,但不足以对系统性能产生不利影响。
Is a Page in Physical Mmeory
为了调试和诊断目的,Linux提供了mincore()函数,该函数可用于确定给定范围的内存是在物理内存中还是交换到磁盘中:
#include
#include
int mincore (void *start, size_t length, unsigned char *vec);
调用通过vec返回向量,并描述从start(必须是页面对齐)开始的页面和length字节的扩展(不需要页面对齐)。vec中的每个字节 从描述第一页的第一个字节开始,然后线性向前移动。
vec 必须大于(length − 1 + page size) / page size
成功返回0, 失败返回-1,并且设置errno。