Арифметика по указателям

Я все еще изучаю указатели. Я знаю о переключении if заявления и тому подобное. В книге, которую я использую, мне привели этот пример:

    FILE* from = fopen("in.txt", "r");
    FILE* to = fopen("out.txt", "w");
    if (from != NULL && to != NULL)
    {
        ...
    }
    else
    {
        printf("failed to open files!\n");
    }
} /* end of function */

Я знаю, что можно изменить на это:

    FILE* from = fopen("in.txt", "r");
    FILE* to = fopen("out.txt", "w");
    if (from == NULL || to == NULL)
    {
        printf("failed to open files!\n");
        return;
    }
    ...
} /* end of function */

Теперь мой вопрос (если он будет скомпилирован), если это безопасно или реализация определяется как NULL отличается практически на каждом компиляторе.

    FILE* from = fopen("in.txt", "r");
    FILE* to = fopen("out.txt", "w");
    if ((from & to) == NULL)
    {
        printf("failed to open files!\n");
        return;
    }
    ...
} /* end of function */

5 ответов

Решение

Нет.

Во-первых, он не должен компилироваться, по крайней мере, если компилятор соответствует стандартам. Указатели не являются допустимыми операндами для побитовых операторов, таких как | а также &,

Во-вторых, даже если ваш компилятор позволяет вам рассматривать указатели как целые числа, вы рискуете несовместимости платформы; Есть реализации C, где они вообще не взаимозаменяемы. Вы можете предположить, что любые такие реализации обязательно будут также совместимы, но предположения редко бывают безопасными...

В-третьих, даже если предположить, что ORing двух указателей работает вместе и дает вам то, что вы можете сравнить с NULLВы изменили смысл теста: (from|to) будет только NULL если оба fopenне удалось; если только один из них завершился успешно, результат будет ненулевым, и ваш код потерпит неудачу.

Нет.

За T *x а также T *y в С выражение x|y бессмысленно, согласно стандарту. Это не должно компилироваться. От n1256 §6.5.12 №2 "Побитовый оператор ИЛИ":

Каждый из операндов должен иметь целочисленный тип.

Это означает, что x|y это ошибка, конец истории. То же самое относится ко всем другим побитовым операторам: &|^~<<>> все они могут использоваться только на целых числах (обратите внимание, что "целые числа" включают символы и bools).

Однако, если вы хотите сэкономить усилия при наборе текста, вполне допустимо использовать логические операторы в указателях.

// x == NULL is exactly semantically equivalent to !x
// These two are exactly the same
if (x == NULL || y == NULL) ...
if (!x || !y) ...

// In a logical expression, x != NULL is exactly semantically equivalent to x
// These two are exactly the same
if (x != NULL && y != NULL) ...
if (x && y) ...

Вам решать, думаете ли вы x == NULL лучше или !x лучше. Вам лучше уметь читать оба, так как оба стиля являются общими.

Никогда не пытайтесь играть в игры с побитовыми операторами и указателями.

Если вы просто ищете более краткий способ написания выражения, это довольно распространенный и идиоматический способ сделать это:

    FILE* from = fopen("in.txt", "r");
    FILE* to = fopen("out.txt", "w");
    if (!from || !to) // note the use of the ! operator
    {
        printf("failed to open files!\n");
        return;
    }
    ...
} /* end of function */

! Оператор является логическим оператором НЕ. Поскольку нулевой указатель всегда имеет значение 0, которое является "ложным" значением, выражение !from означает "правда, если from нулевой указатель, в противном случае false. Также очень хорошо читается: "если не из или не делать, то обработать ошибку"

Точно так же люди пишут код if (from) проверить, не является ли указатель ненулевым.

PS Я знаю, что многие люди любят использовать такие выражения, как FILE* когда объявляю указатели, но мне не нравится эта форма, потому что это ложь. Когда вы объявляете FILE *from это означает "выражение *from имеет тип FILE". Это работает, чтобы положить * сразу после FILE но это заставляет это выглядеть, как это означает "выражение from имеет тип указатель наFILE"Это не так, и вот пример:

FILE* from, to;

from имеет тип "указатель наFILE". Какой тип to? Почему это старая? FILE, а не какой-либо указатель. Вы должны использовать выражение, если вы объявляете их в одной строке:

FILE *from, *to;

Это означает "выражение *from это тип FILEи выражение *to это тип FILEИ похоже, когда вы к этому привыкли.

Вы могли бы написать это, но это непристойно.

FILE* from, *to;

Тьфу!

Побитовые операции недопустимы для указателей.

Вам следует избегать таких упражнений.

from а также to являются указателями, вы не можете делать с ними побитовую операцию. Тем не мение, <stdint.h> обеспечивает intptr_t который имеет целочисленный тип и гарантированно содержит указатель, поэтому приведение ваших указателей к ним будет правильным. Однако это некрасиво, поэтому я бы остановился на более читаемой версии.

Другие вопросы по тегам