我是 C 的新手,我正在學習檔案描述符和使用 open、write、close 函式。我期望的是在 open() 函式之后輸出檔案描述符的 printf 陳述句,以及輸出正在寫入的文本的確認的另一個 printf 陳述句。我得到的是:
.\File.exe "this is a test"
[DEBUG] buffer @ 0x00b815c8: 'this is a test'
[DEBUG] datafile @ 0x00b81638: 'C:\Users\____\Documents\Notes'
在進一步除錯的地方留有空白。該部分的代碼塊是:
strcpy(buffer, argv[1]); //copy first vector into the buffer
printf("[DEBUG] buffer \t @ 0xx: \'%s\'\n", buffer, buffer); //debug buffer
printf("[DEBUG] datafile @ 0xx: \'%s\'\n", datafile, datafile); //debug datafile
strncat(buffer, "\n", 1); //adds a newline
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); //opens file
if(fd == -1)
{
fatal("in main() while opening file");
}
printf("[DEBUG] file descriptor is %d\n", fd);
if(write(fd, buffer, strlen(buffer)) == -1) //wrting data
{
fatal("in main() while writing buffer to file");
}
if(close(fd) == -1) //closing file
{
fatal("in main() while closing file");
}
printf("Note has been saved.");
我基本上是從我正在學習的書中逐字逐句地復制代碼,所以這怎么可能不起作用?
問題是列印陳述句沒有列印任何內容,并且沒有回傳檔案描述符。
這是完整的代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *pnt, char *opnt) //usage function
{
printf("Usage: %s <data to add to \"%s\">", pnt, opnt);
exit(0);
}
void fatal(char*); //fatal function for errors
void *ec_malloc(unsigned int); //wrapper for malloc error checking
int main(int argc, char *argv[]) //initiates argumemt vector/count variables
{
int fd; //file descriptor
char *buffer, *datafile;
buffer = (char*) ec_malloc(100); //buffer given 100 bytes of ec memory
datafile = (char*) ec_malloc(20); //datafile given 20 bytes of ec memory
strcpy(datafile, "C:\\Users\\____\\Documents\\Notes");
if(argc < 2) //if argument count is less than 2 i.e. no arguments provided
{
usage(argv[0], datafile); //print usage message from usage function
}
strcpy(buffer, argv[1]); //copy first vector into the buffer
printf("[DEBUG] buffer \t @ %p: \'%s\'\n", buffer, buffer); //debug buffer
printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile); //debug datafile
strncat(buffer, "\n", 1); //adds a newline
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); //opens file
if(fd == -1)
{
fatal("in main() while opening file");
}
printf("[DEBUG] file descriptor is %d\n", fd);
if(write(fd, buffer, strlen(buffer)) == -1) //wrting data
{
fatal("in main() while writing buffer to file");
}
if(close(fd) == -1) //closing file
{
fatal("in main() while closing file");
}
printf("Note has been saved.");
free(buffer);
free(datafile);
}
void fatal(char *message)
{
char error_message[100];
strcpy(error_message, "[!!] Fatal Error ");
strncat(error_message, message, 83);
perror(error_message);
exit(-1);
}
void *ec_malloc(unsigned int size)
{
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
{
fatal("in ec_malloc() on memory allocation");
return ptr;
}
}
編輯:問題已解決。錯誤的原因是沒有足夠的記憶體分配給 ec_malloc 函式,這意味著無法保存文本。我將位元組值更改為 100,代碼現在可以作業了。
uj5u.com熱心網友回復:
我不確定您使用的是哪種編譯器,但是我嘗試使用 (GCC) 撰寫的代碼的編譯器說:
main.c:34:5: warning: ‘strncat’ specified bound 1 equals source length [-Wstringop-overflow=]
34 | strncat(buffer, "\n", 1); //adds a newline
| ^~~~~~~~~~~~~~~~~~~~~~~~
換句話說,strncat您代碼中的 呼叫是高度可疑的。您正在嘗試附加一個長度為 1 的換行符,您將其作為第三個引數傳遞。但是strncat期望第三個引數是 中的剩余空間buffer,而不是要附加的字串的長度。
正確的呼叫看起來有點像這樣:
size_t bufferLength = 100;
char* buffer = malloc(bufferLength);
strncat(buffer, "\n", (bufferLength - strlen(buffer) - strlen("\n") - 1));
但是,在這種情況下,您可以保存,因為strncat保證結果緩沖區是 NUL 終止的,這意味著它總是超出指定的大小寫入一個額外的位元組。
所有這些都很復雜,并且是錯誤的常見來源。簡單地使用一次snprintf構建整個字串更容易:
size_t bufferLength = 100;
char* buffer = malloc(bufferLength);
snprintf(buffer, bufferLength, "%s\n", argv[1]);
代碼中的另一個錯誤是ec_malloc函式:
void *ec_malloc(unsigned int size)
{
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
{
fatal("in ec_malloc() on memory allocation");
return ptr;
}
}
看看你是否能發現它:會發生什么,如果ptr是不 NULL?嗯,沒什么!在這種情況下,該函式不回傳值;執行剛剛結束。
如果您在 x86 上使用 GCC(可能還有其他編譯器),此代碼似乎可以正常作業,因為該malloc函式的結果將保留在適當的 CPU 暫存器中作為該ec_malloc函式的結果。但是,它恰好在環境的魔力下作業的事實并不能使它成為正確的代碼。它隨時可能停止作業,并應予以修復。該函式值得一個回傳值!
不幸的是,GCC 編譯器無法檢測到這個錯誤,但 Clang 可以:
<source>:64:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
}
^
代碼中的主要錯誤是緩沖區溢位。在頂部,您只為datafile緩沖區分配了 20 個位元組:
datafile = (char*) ec_malloc(20); //datafile given 20 bytes of ec memory
這意味著它只能存盤 20 個字符。但是,您繼續寫了 20 多個字符:
strcpy(datafile, "C:\\Users\\____\\Documents\\Notes");
該字串文字是 33 個字符,不包括終止的 NUL!您需要一個至少有 50 個字符空間的緩沖區來保存所有這些。如果緩沖區太小,strcpy函式呼叫會產生典型的“緩沖區溢位”錯誤,這是一種未定義的行為,表現為破壞程式的記憶體區域并因此過早終止。
同樣,當我嘗試編譯和運行代碼時,GCC 報告:
malloc(): corrupted top size
因為它檢測到您已經超出了動態分配的記憶體(由 回傳malloc)。它能夠做到這一點是因為,在幕后,在分配的記憶體塊之后malloc存盤哨兵資訊,并且您對分配的空間的覆寫已經覆寫了它的哨兵資訊。
整個代碼有點可疑;它不是由非常了解 C 的人撰寫的,也不是由其他任何人除錯或審查的。
這里沒有真正需要使用動態記憶體分配來分配固定大小的緩沖區。如果您打算使用動態記憶體分配,則分配您需要的實際空間量。否則,如果您要分配固定大小的緩沖區,則只需在堆疊上分配。
當您只需使用snprintf.
還有一個額外的提示:在除錯問題時,盡量減少代碼。沒有任何檔案 I/O 內容與此問題相關,因此在分析此代碼時,我將整個部分替換為:
printf("[DEBUG] file descriptor is %d\n", 42);
一旦其余代碼作業正常,我可以回傳并將實際代碼添加回該部分,然后對其進行測驗。(我沒有這樣做,因為我沒有一個方便的檔案系統來測驗這個。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/361331.html
標籤:C
上一篇:Linux內核當前宏的實作
