0

这是一个非常基本的 C 代码片段,用于打开和读取文件:

  int fd = open("test.txt",O_RDONLY);
  char buf[128];
  int reader = read(fd,buf,128);
  int i;
    for (i=0;i<strlen(buf);i++)
    {
        printf("%i: I read: %c", i, (int)buf[i]);
    }

我还包括这些标准标题:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

此代码在 C 中可以正常工作,并且由于 Objective-C 是 CI 的超集,因此希望它在 Obj-C 中也可以正常工作。但相反,我得到了所有垃圾数据,例如:

0: I read: –
1: I read: *
2: I read: :

为什么?

4

4 回答 4

2

您不应该在 read() 的输出缓冲区上使用 strlen - 它不是以空值结尾的。

于 2009-11-28T22:13:21.807 回答
2

您的open通话可能失败。尝试指定文件的完整路径,并进行一些错误检查。

于 2009-11-28T22:19:13.273 回答
1

首先,在 for 语句中调用 strlen() 是一种非常糟糕的做法……除非编译器对其进行优化,否则您的循环将以 N**2 次运行。

其次,你怎么知道缓冲区是零终止的?您在这里做出的假设可能无效。由于您知道缓冲区的大小 (128),因此您应该使用一个常量,例如 BUFSIZE,并且循环中的条件应该是 'i < BUFSIZE'。

第三,将存储在 buf[i] 中的字符值转换为 int,然后将其打印为 char。显然,Objective-C 不像桌面 C 编译器那样做这件事,而且无论如何这在语言中都是弱定义的。最好只引用 buf[i] 而不将其转换为 int。我确定这就是您的问题所在。

于 2009-11-28T22:24:03.920 回答
1

总结到目前为止的反应,并添加我自己的观察:

open()您应该检查和的返回值read()。如果他们失败了,你将盲目地继续打印垃圾。

read()返回读取的字符数,如果出错则返回 -1。它不会以空值终止其缓冲区,因此strlen()用于查找读取的数据量是错误的。

您不应该strlen()在循环测试条件中调用 to,因为您将在每次迭代时重新评估它。

buf[i]声明中的toint的强制转换printf是不必要的。可变参数函数的额外参数printf(即构成 的所有参数...)经过默认参数提升,如下所示:

  • chars、shorts 及其未签名的对应项被提升为ints
  • floats 提升为doubles

如果没有演员表,buf[i]将被隐式提升为int无论如何,因此添加演员表虽然正确,但会使代码对任何阅读它的人更加困惑。

因此,您的代码应如下所示:

int fd = open("test.txt",O_RDONLY);
if(fd < 0)
{
    fprintf(stderr, "open failed: %s\n", strerror(errno));
    return;
}
char buf[128];
// It's better to use sizeof(buf) here, so we don't have to change it in case we
// change the size of buf.  -1 to leave space for the null terminator
int reader = read(fd,buf,sizeof(buf)-1);
if(reader < 0)
{
    fprintf(stderr, "read failed: %s\n", strerror(errno));
    close(fd);
    return;
}
buf[reader] = 0;  // add null terminator for safety
int i;
for (i=0; i < reader; i++)
{
    printf("%i: I read: %c", i, buf[i]);
}
于 2009-11-28T22:37:25.870 回答