gpt4 book ai didi

c - 如何正确地逐字节读取文件而不丢失任何信息

转载 作者:行者123 更新时间:2023-11-30 14:52:05 25 4
gpt4 key购买 nike

我猜真正的目标是成功模仿 strace 关于 read() 的输出。系统调用参数读取它神奇地输出。

为了尽可能清楚地说明这一点:

这意味着它以控制台无法解释的方式显示它们。例如,如果文件包含\0004 或\0104,那么它将把\0004 和\0104 显示为文字字符串(就像您写了\\0004 或\\0104 一样),因此控制台不会解释它。

#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char * argv[]) {
#include <stdio.h>
int shift(int times) {
#ifdef SHIFT_VERBOSE
int shift_mode_verbose = 1;
#else
int shift_mode_verbose = 0;
#endif
if (shift_mode_verbose == 1) {
printf("The following arguments were passed (before) to main(%i):\n", argc);
for(int i=1; i<argc; i++) {
printf("arg%i: %s\n", i, argv[i]);
}
printf("\n");
}
if (shift_mode_verbose == 1) {printf("shifting %i times\n", times);}
for(int t=1; t<times+1; ++t) { // we set this to 1 and respectively increase by 1, to avoid shifting argv[0] as it is holds the program name
for(int i=1; i<argc; ++i) { // we set this to 1 to avoid shifting argv[0] as it is holds the program name
if (shift_mode_verbose == 1) {printf("shift %i: arg%i: %s >", t, i, argv[i]);}
argv[i] = argv[i+1];
if (shift_mode_verbose == 1) {printf(" %s\n", argv[i]);}
}
--argc;
}
if (shift_mode_verbose == 1) {
printf("The following arguments were passed (after) to main(%i):\n", argc);
for(int i=1; i<argc; i++) {
printf("arg%i: %s\n", i, argv[i]);
}
printf("\n");
}
return 0;
}

int fshift(int times) { // a potentially faster version of shift()
times = argc < times ? argc : times;
argc = (argc) - times;
(argv) += times;
return 0;
}
if (argc < 3) {
printf("Usage: %s lines (-1 = all lines), files\n", argv[0]);
return 1;
}
int LINES_TO_READ = atoi(argv[1]);
shift(1);
for (ssize_t i = 1; i < argc; i++) {
const char *filename = argv[i];
printf("printing \"%s\"\n\n", filename);

int fd = open(filename, O_RDONLY);

if (fd < 0) {
printf("cannot open \"%s\", returned %i\n", filename, fd);
return -1;
}

char unsigned ch;
size_t lines = 1;

// Read the file byte by byte
while (read(fd, &ch, 1) == 1) {
if (ch == '\n') {
printf("\\n");
} else if (ch == '\0') {
printf("\\0");
} else if (ch == '\r') {
printf("\\r");
} else if (ch == '\t') {
printf("\\t");
} else if(isprint(ch)) {
printf("%c", ch);
} else {
printf("\\%03o", ch);
}
// FILE *file = fopen(filename, "rb");
// char unsigned ch;
// size_t lines = 1, bytes=1;
// // Read the file byte by byte
// while (fread(&ch, 1, 1, file) == 1) {
// if (ch == '\n') {
// printf("\\n");
// } else if (ch == '\0') {
// printf("\\0");
// } else if (ch == '\r') {
// printf("\\r");
// } else if (ch == '\t') {
// printf("\\t");
// } else if(isprint(ch)) {
// printf("%c", ch);
// } else {
// printf("\\%03o", ch);
// }
if (ch == '\n') {
// Stop if we read 10 lines already
if (lines == LINES_TO_READ) {
break;
}
lines++;
}
}

if (close(fd) < 0) {
printf("cannot close \"%s\"\n", filename);
return -1;
}
printf("\n");
}
return 0;
}

下面是它应该是什么样子的示例(除了 ./catraw 的输出是不正确的)。 (ELF header 和指令是从 nasmstrace 和 c at 获取的。)

elf_header='\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0\3\0\1\0\0\0T\200\4\0104\0\0\0\0\0\0\0\0\0\0\0004\0 \0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\200\4\10\0\200\4\10T\0\0\0T\0\0\0\5\0\0\0\0\20\0\0'
instructions='\263*f1\300f@\315\200'
printf "$elf_header$instructions" > return_42
chmod +x return_42
./return_42 # test run to see if it actually works
echo $? # echo return code of ./return_42
strace -s 4096 cat ./return_42
gcc catraw.c --static -o catraw
strace ./catraw -1 ./return_42
./catraw -1 ./return_42

[PROGRAM ] \177ELF\001\001\001\0\0\0\0\0\0\0\0\0\002\0\003\0\001\0\0\0T\200\004\0104\0\0\0\0\0\0\0\0\0\0\04\0 \0\001\0\0\0\0\0\0\0\001\0\0\0\0\0\0\0\0\200\004\010\0\200\004\010T\0\0\0T\0\0\0\005\0\0\0\0\020\0\0\263*f1\300f@\315\200

最佳答案

这有点不清楚(不确定所有的程序集),但类似这样:

#include <ctype.h>

// Format the character 'c' (which should be cast from char) into a
// string. Will use backslash-escaped form for non-printables.
void tostring(char *buf, size_t buf_max, unsigned int c)
{
if(isprint(c))
{
snprintf(buf, buf_max, "%c", c);
}
else
{
snprintf(buf, buf_max, "\\%3o", c);
}
}

当使用 c = 0177 调用时,会构建 "\177"

是的,显然第一种情况下对 snprintf() 的调用可以被分解为可打印的内容。

关于c - 如何正确地逐字节读取文件而不丢失任何信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47767350/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com