Stack-Based Allocations
要從棧中進行動態(tài)內(nèi)存分配,請使用alloca()系統(tǒng)調(diào)用:
#include <alloca.h>
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 <string.h>
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,則在函數(shù)返回之前不會釋放內(nèi)存祝懂。使用VLA確保在循環(huán)的每一次迭代中釋放內(nèi)存票摇。因此,使用VLA消耗最多n個字節(jié)砚蓬,而Alloca()則消耗n*(n+1)/2個字節(jié)矢门。
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 <string.h>
void * memset (void *s, int c, size_t n);
對memset()的調(diào)用將從s開始的n個字節(jié)設置為字節(jié)c并返回s。
#include <strings.h>
void bzero (void *s, size_t n);
請注意怜械,bzero()(以及其他b接口)需要頭<strings.h>而不是<string.h>颅和。
Comparing Bytes
#include <string.h>
int memcmp (const void *s1, const void *s2, size_t n);
s1 = s2: return 0
s1 < s2: return <0
s1 > s2: return >0
#include <strings.h>
int bcmp (const void *s1, const void *s2, size_t n);
0的話相等,否則不相等缕允。
比較兩個結(jié)構(gòu)體的話用memcmp是不安全的, 如下:
/* are two dinghies identical? (BROKEN) */
int compare_dinghies (struct dinghy *a, struct dinghy *b) {
return memcmp (a, b, sizeof (struct dinghy));
}
如果要比較結(jié)構(gòu)體的話,我們應該比較結(jié)構(gòu)體中的每個元素蹭越。
/* 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 <string.h>
void * memmove (void *dst, const void *src, size_t n);
#include <strings.h>
void bcopy (const void *src, void *dst, size_t n);
上面這兩個是是支持overlapping(dst的一部分在src中)
但是下面這個是不支持overlapping的障本,更塊:
#include <string.h>
void * memcpy (void *dst, const void *src, size_t n);
還有一種:
#include <string.h>
void * memccpy (void *dst, const void *src, int c, size_t n);
與memcpy()相同,只是如果函數(shù)在src的前n個字節(jié)內(nèi)找到字節(jié)c,則停止復制驾霜。調(diào)用返回在c之后指向dst中下一個字節(jié)的指針案训,如果沒有找到c,則返回NULL粪糙。 .
最后强霎,您可以使用mempcpy()來逐步遍歷內(nèi)存:
#define GNU_Source
#include<string.h>
void*mempcpy(void*dst,const void*src蓉冈,size_tn)城舞;
mempcpy()函數(shù)執(zhí)行與memcpy()相同的操作。只不過它返回一個指針寞酿,指向上次復制的字節(jié)之后的下一個字節(jié)家夺。如果要將一組數(shù)據(jù)復制到連續(xù)的內(nèi)存位置,這是很有用的伐弹。但它并不是一個改進者 因為返回值僅僅是dst+n拉馋,這個函數(shù)是特定于GNU的。
Searching Bytes
#include <string.h>
void * memchr (const void *s, int c, size_t n);
函數(shù)對s指向的n個字節(jié)的內(nèi)存進行c字符掃描惨好,調(diào)用返回第一個與c匹配的字節(jié)的指針煌茴,如果未找到c,則返回NULL日川。
#define _GNU_SOURCE
#include <string.h>
void * memrchr (const void *s, int c, size_t n);
與memrchr()與memchr()是一樣的景馁,但是是逆序查找。
#define _GNU_SOURCE
#include <string.h>
void * memmem (const void *haystack,
size_t haystacklen,
const void *needle,
size_t needlelen);
在haystack中查找needle逗鸣,找到返回指針合住,找不到返回NULL。
Frobnicating Bytes
#define _GNU_SOURCE
#include <string.h>
void * memfrob (void *s, size_t n);
對memfrob()的調(diào)用掩蓋了從s開始的內(nèi)存的前n個字節(jié)
再次調(diào)用將返回原來的值撒璧。
Locking Memory
Locking Part of an Address Space
#include <sys/mman.h>
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 <sys/mman.h>
int mlockall (int flags);
flags參數(shù)列表:
- MCL_Current 將當前映射的所有頁面(堆棧卿樱、數(shù)據(jù)段僚害、映射文件等)鎖定到進程的地址空間中。
- MCL_WORVERY繁调,確保將來映射到地址空間的所有頁也被鎖定在內(nèi)存中萨蚕。
成功返回0,失敗返回-1蹄胰,并設置errno岳遥。
Unlocking Memory
#include <sys/mman.h>
int munlock (const void *addr, size_t len);
int munlockall (void);
成功返回0, 失敗返回-1裕寨,并且設置errno浩蓉。
Locking Limits
擁有CAP_IPC_LOCK功能的進程可能會將任意數(shù)量的頁面鎖定到內(nèi)存中派继。沒有此功能的進程可能只鎖定RLIMIT_MEMLOCK字節(jié)。
默認情況下捻艳,此資源限制為32KB-足夠大驾窟,可鎖定內(nèi)存中的一個或兩個密碼,但不足以對系統(tǒng)性能產(chǎn)生不利影響认轨。
Is a Page in Physical Mmeory
為了調(diào)試和診斷目的绅络,Linux提供了mincore()函數(shù),該函數(shù)可用于確定給定范圍的內(nèi)存是在物理內(nèi)存中還是交換到磁盤中:
#include <unistd.h>
#include <sys/mman.h>
int mincore (void *start, size_t length, unsigned char *vec);
調(diào)用通過vec返回向量嘁字,并描述從start(必須是頁面對齊)開始的頁面和length字節(jié)的擴展(不需要頁面對齊)恩急。vec中的每個字節(jié) 從描述第一頁的第一個字節(jié)開始,然后線性向前移動拳锚。
vec 必須大于(length ? 1 + page size) / page size
成功返回0假栓, 失敗返回-1,并且設置errno霍掺。