Арифметика по указателям
Я все еще изучаю указатели. Я знаю о переключении 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
который имеет целочисленный тип и гарантированно содержит указатель, поэтому приведение ваших указателей к ним будет правильным. Однако это некрасиво, поэтому я бы остановился на более читаемой версии.