[英]malloc() and memset() behavior
我寫了一些代碼來看看malloc()
和memset()
行為,我發現了一個我不知道發生了什么的情況。
我使用malloc()
為字符數組分配15個字節的內存,我想看看如果我錯誤地使用memset()
在我創建的指針中設置100個字節的內存會發生什么。 我希望看到memset()
設置了15個字節(並且可能會丟棄一些其他內存)。 我在運行程序時看到的是它為我編碼的字符設置了26個字節的內存。
知道為什么為我創建的指針分配了26個字節? 我正在用gcc和glibc編譯。 這是代碼:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define ARRLEN 14
int main(void) {
/* + 1 for the null terminator */
char *charptr = malloc((sizeof(*charptr) * ARRLEN) + 1);
if (!charptr)
exit(EXIT_FAILURE);
memset(charptr, '\0', (sizeof(*charptr) * ARRLEN) + 1);
/* here's the intentionally incorrect call to memset() */
memset(charptr, 'a', 100);
printf("sizeof(char) ------ %ld\n", sizeof(char));
printf("sizeof(charptr) --- %ld\n", sizeof(charptr));
printf("sizeof(*charptr) --- %ld\n", sizeof(*charptr));
printf("sizeof(&charptr) --- %ld\n", sizeof(&charptr));
printf("strlen(charptr) --- %ld\n", strlen(charptr));
printf("charptr string ---- >>%s<<\n", charptr);
free(charptr);
return 0;
}
這是我得到的輸出:
sizeof(char) ------ 1
sizeof(charptr) --- 8
sizeof(*charptr) --- 1
sizeof(&charptr) --- 8
strlen(charptr) --- 26
charptr string ---- >>aaaaaaaaaaaaaaaaaaaaaaaa<<
首先,這是未定義的行為,所以任何事情都可能發生; 正如在評論中所說,在我的機器上,我得到了完全相同的行為,禁用了優化,但啟用了優化,我得到一個關於編譯時潛在緩沖區溢出的警告(令人印象深刻的作業gcc!)和運行時的大崩潰。 更好的是,如果我在printf
調用之前使用puts
打印它,我會使用不同數量的a
打印它。
盡管如此,我仍然懷有與你完全相同的行為,所以讓我們來調查一下。 我編譯了你的程序沒有優化和調試信息
[matteo@teokubuntu ~/scratch]$ gcc -g memset_test.c
然后我啟動了調試器並在memset
之后的第一個printf
上添加了一個斷點。
Reading symbols from a.out...done.
(gdb) break 20
Breakpoint 1 at 0x87e: file memset_test.c, line 20.
(gdb) r
Starting program: /home/matteo/scratch/a.out
Breakpoint 1, main () at memset_test.c:20
20 printf("sizeof(char) ------ %ld\n", sizeof(char));
現在我們可以在charptr
指向的第26個內存位置設置硬件寫斷點
(gdb) p charptr
$1 = 0x555555756260 'a' <repeats 100 times>
(gdb) watch charptr[26]
Hardware watchpoint 2: charptr[26]
... 所以...
(gdb) c
Continuing.
Hardware watchpoint 2: charptr[26]
Old value = 97 'a'
New value = 0 '\000'
_int_malloc (av=av@entry=0x7ffff7dcfc40 <main_arena>, bytes=bytes@entry=1024) at malloc.c:4100
4100 malloc.c: File o directory non esistente.
(gdb) bt
#0 _int_malloc (av=av@entry=0x7ffff7dcfc40 <main_arena>, bytes=bytes@entry=1024) at malloc.c:4100
#1 0x00007ffff7a7b0fc in __GI___libc_malloc (bytes=1024) at malloc.c:3057
#2 0x00007ffff7a6218c in __GI__IO_file_doallocate (fp=0x7ffff7dd0760 <_IO_2_1_stdout_>) at filedoalloc.c:101
#3 0x00007ffff7a72379 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7dd0760 <_IO_2_1_stdout_>) at genops.c:365
#4 0x00007ffff7a71498 in _IO_new_file_overflow (f=0x7ffff7dd0760 <_IO_2_1_stdout_>, ch=-1) at fileops.c:759
#5 0x00007ffff7a6f9ed in _IO_new_file_xsputn (f=0x7ffff7dd0760 <_IO_2_1_stdout_>, data=<optimized out>, n=23)
at fileops.c:1266
#6 0x00007ffff7a3f534 in _IO_vfprintf_internal (s=0x7ffff7dd0760 <_IO_2_1_stdout_>,
format=0x5555555549c8 "sizeof(char) ------ %ld\n", ap=ap@entry=0x7fffffffe330) at vfprintf.c:1328
#7 0x00007ffff7a48f26 in __printf (format=<optimized out>) at printf.c:33
#8 0x0000555555554894 in main () at memset_test.c:20
(gdb)
因此,它只是通過printf
調用malloc
代碼(或多或少地間接),在內存塊上執行它的東西,緊鄰它給你的內存塊(可能將其標記為已使用)。
長話短說:你記憶的不是你的記憶,現在它在第一次需要的時候被其合法的主人修改了; 沒什么特別奇怪或有趣的。
我使用malloc()為字符數組分配15個字節的內存,我想看看如果我錯誤地使用memset()在我創建的指針中設置100個字節的內存會發生什么。
就語言標准而言, 未定義的行為會發生什么,並且在特定情況下實際發生的任何事情都無法從源代碼中預測到,並且可能在不同的C實現或甚至同一程序的不同運行中不一致。
我希望看到memset()設置了15個字節(並且可能會丟棄一些其他內存)。
這將是一個看似合理的結果,但你有任何特別的期望是危險的。 不要假設您可以預測UB會采取什么樣的表現,甚至不能根據過去的經驗來預測。 既然你不應該這樣做,也不能從那個方面學到任何有用的東西,那么試驗UB是不值得的。
我在運行程序時看到的是它為我編碼的字符設置了26個字節的內存。
知道為什么為我創建的指針分配了26個字節?
誰說你的實驗表明情況如此? 不僅memset()
而且最后的printf()
展示了UB。 除了輸出之外,輸出告訴你什么。 那時。
現在一般情況下, malloc
可能會保留比您要求的更大的塊。 許多實現在內部管理大於一個字節的塊的內存,例如16或32字節。 但是,對於程序行為的定義,這與這種或那種方式無關,並且它與您的輸出無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.