Почему следующий (совершенно допустимый) код C не показывает содержимое файла в Objective-C? - PullRequest
0 голосов
/ 29 ноября 2009

Вот очень простой фрагмент кода 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 является надмножеством C, я ожидал, что он будет работать и в Obj-C. Но вместо этого я получаю все данные мусора, такие как:

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

Почему?

Ответы [ 4 ]

2 голосов
/ 29 ноября 2009

Ваш open вызов, вероятно, не удался. Попробуйте указать полный путь к файлу и используйте проверку ошибок.

2 голосов
/ 29 ноября 2009

Вы не должны использовать strlen в буфере вывода из read () - он не заканчивается нулем.

1 голос
/ 29 ноября 2009

Подведение итогов ответов и добавление моих собственных наблюдений:

Вы должны проверить возвращаемое значение из open() и read(). Если они потерпят неудачу, вы будете слепо продолжать и печатать мусор.

read() возвращает количество прочитанных символов или -1 в случае ошибки. Он НЕ заканчивает нулем свой буфер, поэтому использование strlen() для определения количества прочитанных данных неверно.

Вы не должны помещать вызов strlen() в условие проверки цикла, поскольку вы будете переоценивать его каждую итерацию.

Приведение buf[i] к int в операторе printf не требуется. Дополнительные аргументы для функций с переменными значениями, такие как printf (то есть все аргументы, составляющие ...), переносятся по умолчанию следующим образом:

  • char с, short с и их неподписанные аналоги повышаются до int с
  • float с повышены до double с

Без приведения 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]);
}
1 голос
/ 29 ноября 2009

Во-первых, вызов strlen () в вашем операторе for является очень плохой практикой ... если компилятор не оптимизирует его, ваш цикл будет выполняться в порядке N ** 2 раза. *

Во-вторых, как вы узнаете, что буфер заканчивается нулем? Вы делаете здесь предположение, которое может быть недействительным. Так как вы знаете размер буфера (128), вы должны использовать константу, например, BUFSIZE, а условием в цикле должно быть «i

В-третьих, вы приводите значение символа, хранящегося в buf [i], к типу int, а затем печатаете его как символ. Очевидно, что Objective-C не делает это так же, как ваш компилятор C на рабочем столе, и это в любом случае слабо определено в языке. Было бы лучше просто сослаться на buf [i], не приводя его к int. Я уверен, что это где ваша проблема.

...