为什么我不能写入我用 calloc 创建的已分配内存?
Why am I not able to write in the allocated memory that I created with calloc?
我正在编写的 C 代码有问题,但我找不到根本原因。我想做的是从任何目录读取一个文本文件,并通过使用 calloc 分配内存(让它在 0s 中)将所有字节放入堆中
问题是当文件超过一定大小(>=25 KB,可能更小)时,我无法在分配的内存中写入任何内容,但我可以读取文件!
char* ReadBytesFromFile(string fileName[]) {
FILE* fileStream = (FILE*)fopen(fileName, "r");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
char* bytes;
char byteFromFile = 0;
do
{
bytes = (char*)calloc((size_t)fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
for(long i = 0; i < fileSizeInBytes; i++)
{
byteFromFile = (char)getc(fileStream);
if (byteFromFile == EOF) break;
bytes[i] = byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
顺便说一句:
typedef const char string;
typedef signed long int fSz;
另一个线索是我在没有 IDE 的情况下使用 GCC 11.2.0 和以下标志(在 Makefile 中)写这篇文章:
_compilerOptions = -O0 \
-pedantic \
-Wall \
-Wextra \
-Wdiscarded-qualifiers \
-Wwrite-strings \
-ggdb3 \
我知道代码还不是“安全的”,但我不知道是什么导致了这个错误。
当我调试时,我通过打印 byteFromFile 一次看到每个字符,但是当我打印 bytes 时,没有任何内容被写入。
文件大小是我唯一的线索,因为代码适用于 1-5 KB 左右的文件,但大于 1-5 KB 的文件不起作用。
有什么想法或者我做错了什么吗? :(
更新 1:
我已经更新代码如下:
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
但我仍然遇到同样的问题(我正在使用 GDB):
更新二:
我用于测试的文件可以使用以下代码创建:
FILE* fp = (FILE*)fopen("test.txt", "wb");
char byte = 0x0U;
for(int i = 0; i < 4095; i++)
{
(void)putc(byte, fp);
byte++;
}
fclose(fp);
我希望看到的是 bytes 数组中的文件内容。使用代码生成我用作示例的文件我应该看到:“[=88=]0[=88=]1[=88=]2[=88=]3[=88=]4[=88=]5[=88=]6[=88=]7[=88=]8[=88=]901\ ...5[=89=]0[=89=]1[=89=]2...” 根据调试器,GDB 以八进制打印该信息,但我12月写的
上传整个代码很复杂,因为它被分成几个文件。但基本上应该是这样的:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "fileRW.h"
/* ****************************** Typedefs ****************************** */
// Char/strings
typedef unsigned char uchar;
typedef const char string;
// Numerical
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long uint64;
typedef signed char BYTE;
typedef signed short WORD;
typedef signed int DWORD;
typedef signed int long QWORD;
typedef unsigned char uBYTE;
typedef unsigned short uWORD;
typedef unsigned int uDWORD;
typedef unsigned int long uQWORD;
typedef signed long int fSz;
/* ****************************** Function Prototypes ****************************** */
off_t GetFileSizeInBytes(string fileName[]);
char* ReadBytesFromFile(string fileName[]);
void ConvertByteToHexFromFile(uBYTE* inputChar);
int main(int argc, char* argv[])
{
if(argc > 1)
{
for(int i = 1; i < argc; i++)
{
(void)ReadBytesFromFile(argv[i]);
}
}
return 0;
}
off_t GetFileSizeInBytes(const char fileName[])
{
struct stat st;
if(stat(fileName, &st) == 0)
{
return st.st_size;
}
else
{
return -1;
}
}
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName) + 1;
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)malloc(fileSizeInBytes * sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
//(void)fread(bytes, fileSizeInBytes, 1, fileStream);
fclose(fileStream);
return bytes;
}
GCC -v 的输出是:
gcc main.c fileRW.c -c -std=c11 -O0 -pedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -ggdb3 -v -D _ENABLE_DEBUG_CODE_=0
Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0/configure --srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --disable-bootstrap --enable-languages=c,c++,fortran,lto,objc,obj-c++,jit --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (GCC)
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 main.c -quiet -dumpbase main.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o main.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 fileRW.c -quiet -dumpbase fileRW.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o fileRW.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
windres icon.rs icon.o
gcc main.o fileRW.o icon.o -o code.exe
到目前为止,代码才刚刚开始“成型”,所以它仍然很简单。我把所有的 SW 单元都用一个代码粉碎了(只是为了这个问题),但现在它至少在 5 个文件中。
另外,我忘了说我正在使用 Cygwin。我应该换成 MinGW 吗?
更新 3:
大家好,我已经听从了你们的一些建议,我想我已经找到了根本原因。
所以我发现当二进制文件以 0x00 开头时,这会导致一些问题阻止我写入分配的内存。例如,如果我打开一个以 0x1(或 >0x0)开头的二进制文件,代码似乎可以正常工作。例如,我试图读取一个可执行文件,在短时间内似乎工作正常,但一旦找到 0x0,它就会崩溃并且不再写入内存:/
我正在(暂时)实施的解决方法是避免将 0 全部写入。像这样:
...
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
if(byteFromFile != '[=17=]') bytes[counter++] = (char)byteFromFile;
}
...
这当然会导致问题,因为我将无法在我的二进制文件中写入(或读取)0,这不太现实。
更新四:
大家好,“根本原因”是GBD。如果我按照上一个答案的说明(我不能@我的朋友),“问题”就不再是“问题”了。
无论如何,感谢大家的时间。我怎样才能关闭这张票哈哈?
Any ideas or what am I doing wrong? :(
257
getc()
returns unsigned char
和 EOF
范围内的 257 个不同值。保存在 char
中会丢失信息,并可能导致有效输入字节被误解为 EOF
信号(当 char
是 已签名 时)或 byteFromFile == EOF
永远不会是真的(当 char
是 unsigned)。
// char byteFromFile = 0;
int byteFromFile = 0;
...
// byteFromFile = (char)getc(fileStream);
byteFromFile = getc(fileStream);
if (byteFromFile == EOF) break;
循环的早期退出解释了“代码适用于 1-5 KB 左右的文件,但大于 1-5 KB 的文件不起作用。”
尺码
确保文件大小 fileSizeInBytes + 1
不超过 size_t
math.
//add
if (fileSizeInBytes < 0 || fileSizeInBytes >= SIZE_MAX) {
fprintf(stderr, "File size trouble %lld\n", (long long) fileSizeInBytes);
exit (-1);
}
一次就够
重复失败的内存分配没有多大用处。如果第一次失败,以后就不太可能工作了。
// do {
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
// } while (bytes == NULL);
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
if (bytes == NULL) {
fprintf(stderr, "Out of memory\n");
exit (-1);
}
次要:不需要强制转换,引用对象的大小
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
bytes = calloc(fileSizeInBytes + 1, sizeof *bytes);
避免混合类型
为什么代码类型 fileSizeInBytes
和 i
不同?
(在 OP 的情况下看起来不错,因为 现在 ,fsz
是 long
)。
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
...
//for(long i = 0; i < fileSizeInBytes; i++)
for(fSz i = 0; i < fileSizeInBytes; i++)
缺少错误检查
检查以确保文件打开成功。
FILE* fileStream = (FILE*)fopen(fileName, "rb");
// add
if (fileStream == NULL) {
fprintf(stderr, "Fail to open <%s>\n", fileName);
exit (-1);
}
缺少空字符
(使用malloc()
时。)
当然 ReadBytesFromFile()
应该 return 一个指向 字符串 的指针。到目前为止它还没有,因为 bytes[]
缺少某个 空字符 .
char* ReadBytesFromFile(string fileName[]) {
...
bytes[counter] = '[=16=]'; // add
return bytes;
}
施法
OP 代码在多处使用强制转换 ()
。 IMO,所有这些都是不必要的或可能隐藏的问题。它们都需要移除或重新加工。
可能还有其他问题
So what I have found is that when a binary file starts with 0x00, this is causing some issue that prevents me to write in my allocated memory. If for example I open a binary file that starts with 0x1 (or >0x0) the code seems to work kind of OK. I've trying to read an executable file for example and for a short period of time seems to be working OK, but as soon as it finds a 0x0 it crashed and it no longer writes to the memory :/
事实上,您的代码写入内存就很好。但是,您在 GDB 中使用 print bytes
检查它。由于 bytes
的类型为 char *
,GDB 的默认设置是将其打印为字符串,这意味着它只打印字符,直到遇到空字节。如果第一个字节为空,则 GDB 将其打印为空字符串并忽略之后的任何内容。
要指定要转储的字节数,您可以改用 x
命令。例如,x/17xb bytes
将以十六进制转储前 17 个字节;那么您应该看到文件中的实际字节数。如果您想将它们视为可打印字符,则可以执行 x/17cb
。使用 help x
获取更多信息。
(作为一个单独的问题,如果在您的 stat
调用之后其他一些进程应该向文件写入更多字节,那么您的 fgetc
循环将读取太多字符并溢出您的缓冲区。你应该跟踪您实际存储了多少字节,并在缓冲区满时退出或扩大缓冲区。)
我正在编写的 C 代码有问题,但我找不到根本原因。我想做的是从任何目录读取一个文本文件,并通过使用 calloc 分配内存(让它在 0s 中)将所有字节放入堆中
问题是当文件超过一定大小(>=25 KB,可能更小)时,我无法在分配的内存中写入任何内容,但我可以读取文件!
char* ReadBytesFromFile(string fileName[]) {
FILE* fileStream = (FILE*)fopen(fileName, "r");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
char* bytes;
char byteFromFile = 0;
do
{
bytes = (char*)calloc((size_t)fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
for(long i = 0; i < fileSizeInBytes; i++)
{
byteFromFile = (char)getc(fileStream);
if (byteFromFile == EOF) break;
bytes[i] = byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
顺便说一句:
typedef const char string;
typedef signed long int fSz;
另一个线索是我在没有 IDE 的情况下使用 GCC 11.2.0 和以下标志(在 Makefile 中)写这篇文章:
_compilerOptions = -O0 \
-pedantic \
-Wall \
-Wextra \
-Wdiscarded-qualifiers \
-Wwrite-strings \
-ggdb3 \
我知道代码还不是“安全的”,但我不知道是什么导致了这个错误。 当我调试时,我通过打印 byteFromFile 一次看到每个字符,但是当我打印 bytes 时,没有任何内容被写入。
文件大小是我唯一的线索,因为代码适用于 1-5 KB 左右的文件,但大于 1-5 KB 的文件不起作用。
有什么想法或者我做错了什么吗? :(
更新 1:
我已经更新代码如下:
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
但我仍然遇到同样的问题(我正在使用 GDB):
更新二:
我用于测试的文件可以使用以下代码创建:
FILE* fp = (FILE*)fopen("test.txt", "wb");
char byte = 0x0U;
for(int i = 0; i < 4095; i++)
{
(void)putc(byte, fp);
byte++;
}
fclose(fp);
我希望看到的是 bytes 数组中的文件内容。使用代码生成我用作示例的文件我应该看到:“[=88=]0[=88=]1[=88=]2[=88=]3[=88=]4[=88=]5[=88=]6[=88=]7[=88=]8[=88=]901\ ...5[=89=]0[=89=]1[=89=]2...” 根据调试器,GDB 以八进制打印该信息,但我12月写的
上传整个代码很复杂,因为它被分成几个文件。但基本上应该是这样的:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "fileRW.h"
/* ****************************** Typedefs ****************************** */
// Char/strings
typedef unsigned char uchar;
typedef const char string;
// Numerical
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long uint64;
typedef signed char BYTE;
typedef signed short WORD;
typedef signed int DWORD;
typedef signed int long QWORD;
typedef unsigned char uBYTE;
typedef unsigned short uWORD;
typedef unsigned int uDWORD;
typedef unsigned int long uQWORD;
typedef signed long int fSz;
/* ****************************** Function Prototypes ****************************** */
off_t GetFileSizeInBytes(string fileName[]);
char* ReadBytesFromFile(string fileName[]);
void ConvertByteToHexFromFile(uBYTE* inputChar);
int main(int argc, char* argv[])
{
if(argc > 1)
{
for(int i = 1; i < argc; i++)
{
(void)ReadBytesFromFile(argv[i]);
}
}
return 0;
}
off_t GetFileSizeInBytes(const char fileName[])
{
struct stat st;
if(stat(fileName, &st) == 0)
{
return st.st_size;
}
else
{
return -1;
}
}
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName) + 1;
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)malloc(fileSizeInBytes * sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
//(void)fread(bytes, fileSizeInBytes, 1, fileStream);
fclose(fileStream);
return bytes;
}
GCC -v 的输出是:
gcc main.c fileRW.c -c -std=c11 -O0 -pedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -ggdb3 -v -D _ENABLE_DEBUG_CODE_=0
Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0/configure --srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --disable-bootstrap --enable-languages=c,c++,fortran,lto,objc,obj-c++,jit --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (GCC)
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 main.c -quiet -dumpbase main.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o main.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 fileRW.c -quiet -dumpbase fileRW.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o fileRW.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
windres icon.rs icon.o
gcc main.o fileRW.o icon.o -o code.exe
到目前为止,代码才刚刚开始“成型”,所以它仍然很简单。我把所有的 SW 单元都用一个代码粉碎了(只是为了这个问题),但现在它至少在 5 个文件中。
另外,我忘了说我正在使用 Cygwin。我应该换成 MinGW 吗?
更新 3:
大家好,我已经听从了你们的一些建议,我想我已经找到了根本原因。
所以我发现当二进制文件以 0x00 开头时,这会导致一些问题阻止我写入分配的内存。例如,如果我打开一个以 0x1(或 >0x0)开头的二进制文件,代码似乎可以正常工作。例如,我试图读取一个可执行文件,在短时间内似乎工作正常,但一旦找到 0x0,它就会崩溃并且不再写入内存:/
我正在(暂时)实施的解决方法是避免将 0 全部写入。像这样:
...
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
if(byteFromFile != '[=17=]') bytes[counter++] = (char)byteFromFile;
}
...
这当然会导致问题,因为我将无法在我的二进制文件中写入(或读取)0,这不太现实。
更新四:
大家好,“根本原因”是GBD。如果我按照上一个答案的说明(我不能@我的朋友),“问题”就不再是“问题”了。
无论如何,感谢大家的时间。我怎样才能关闭这张票哈哈?
Any ideas or what am I doing wrong? :(
257
getc()
returns unsigned char
和 EOF
范围内的 257 个不同值。保存在 char
中会丢失信息,并可能导致有效输入字节被误解为 EOF
信号(当 char
是 已签名 时)或 byteFromFile == EOF
永远不会是真的(当 char
是 unsigned)。
// char byteFromFile = 0;
int byteFromFile = 0;
...
// byteFromFile = (char)getc(fileStream);
byteFromFile = getc(fileStream);
if (byteFromFile == EOF) break;
循环的早期退出解释了“代码适用于 1-5 KB 左右的文件,但大于 1-5 KB 的文件不起作用。”
尺码
确保文件大小 fileSizeInBytes + 1
不超过 size_t
math.
//add
if (fileSizeInBytes < 0 || fileSizeInBytes >= SIZE_MAX) {
fprintf(stderr, "File size trouble %lld\n", (long long) fileSizeInBytes);
exit (-1);
}
一次就够
重复失败的内存分配没有多大用处。如果第一次失败,以后就不太可能工作了。
// do {
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
// } while (bytes == NULL);
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
if (bytes == NULL) {
fprintf(stderr, "Out of memory\n");
exit (-1);
}
次要:不需要强制转换,引用对象的大小
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
bytes = calloc(fileSizeInBytes + 1, sizeof *bytes);
避免混合类型
为什么代码类型 fileSizeInBytes
和 i
不同?
(在 OP 的情况下看起来不错,因为 现在 ,fsz
是 long
)。
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
...
//for(long i = 0; i < fileSizeInBytes; i++)
for(fSz i = 0; i < fileSizeInBytes; i++)
缺少错误检查
检查以确保文件打开成功。
FILE* fileStream = (FILE*)fopen(fileName, "rb");
// add
if (fileStream == NULL) {
fprintf(stderr, "Fail to open <%s>\n", fileName);
exit (-1);
}
缺少空字符
(使用malloc()
时。)
当然 ReadBytesFromFile()
应该 return 一个指向 字符串 的指针。到目前为止它还没有,因为 bytes[]
缺少某个 空字符 .
char* ReadBytesFromFile(string fileName[]) {
...
bytes[counter] = '[=16=]'; // add
return bytes;
}
施法
OP 代码在多处使用强制转换 ()
。 IMO,所有这些都是不必要的或可能隐藏的问题。它们都需要移除或重新加工。
可能还有其他问题
So what I have found is that when a binary file starts with 0x00, this is causing some issue that prevents me to write in my allocated memory. If for example I open a binary file that starts with 0x1 (or >0x0) the code seems to work kind of OK. I've trying to read an executable file for example and for a short period of time seems to be working OK, but as soon as it finds a 0x0 it crashed and it no longer writes to the memory :/
事实上,您的代码写入内存就很好。但是,您在 GDB 中使用 print bytes
检查它。由于 bytes
的类型为 char *
,GDB 的默认设置是将其打印为字符串,这意味着它只打印字符,直到遇到空字节。如果第一个字节为空,则 GDB 将其打印为空字符串并忽略之后的任何内容。
要指定要转储的字节数,您可以改用 x
命令。例如,x/17xb bytes
将以十六进制转储前 17 个字节;那么您应该看到文件中的实际字节数。如果您想将它们视为可打印字符,则可以执行 x/17cb
。使用 help x
获取更多信息。
(作为一个单独的问题,如果在您的 stat
调用之后其他一些进程应该向文件写入更多字节,那么您的 fgetc
循环将读取太多字符并溢出您的缓冲区。你应该跟踪您实际存储了多少字节,并在缓冲区满时退出或扩大缓冲区。)