Arithmetic On Pointers
-
18-06-2021 - |
문제
I'm still learning about pointers. I know about switching up if
statements and such. In the book i'm using, I was given this example:
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 */
I know that can be changed to this:
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 */
Now, my question (if it will compile) is if this is safe or implementation defined as NULL
is different on virtually every compiler.
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 */
해결책
No.
First, it shouldn't compile, at least not if the compiler is standards-conformant. Pointers are not valid operands for bitwise operators like |
and &
.
Second, even if your compiler lets you treat pointers as integers, you risk platform incompatibilities; there are C implementations where they're not at all interchangeable. You might assume any such implementations would necessarily also be conformant, but assumptions are rarely safe...
Third, even assuming that ORing two pointers together works, and gets you something that you can compare with NULL
, you've changed the sense of the test: (from|to)
will only be NULL
if both fopen
s failed; if just one of them succeeded, the result will be nonzero and your code will fail.
다른 팁
No.
For T *x
and T *y
in C, the expression x|y
is meaningless, according to the standard. It should not compile. From n1256 §6.5.12 ¶2 "Bitwise inclusive OR operator":
Each of the operands shall have integer type.
This means that x|y
is an error, end of story. The same applies to all other bitwise operators: &
|
^
~
<<
>>
are all only usable on integers (note that "integers" include characters and bools).
However, if you want to save effort typing, it is perfectly valid to use logical operators on pointers.
// 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) ...
It is up to you whether you think x == NULL
is better or !x
is better. You had better be able to read both, since both styles are common.
Don't ever try to play games with bitwise operators and pointers.
If you are just looking for a more terse way to write the expression, this is a pretty common and idiomatic way to do this:
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 */
The !
operator is a logical NOT operator. Since the null pointer always has a value of 0, which is a "false" value, the expression !from
means "true if from
is a null pointer, otherwise false`. It reads pretty well also: "if not from, or not to, then handle an error"
Likewise, people write code like if (from)
to check if a pointer is non-NULL.
P.S. I know many people like to use expressions like FILE*
when declaring pointers, but I dislike this form, because it is a lie. When you declare FILE *from
this means "the expression *from
has type FILE
". It works to put the *
right after the FILE
but this makes it look like this means "the expression from
has type pointer-to-FILE
". It doesn't, and here's an example:
FILE* from, to;
from
has type "pointer-to-FILE
". What type is to
? Why it is plain old FILE
, not any sort of pointer. The expression you need to use, if you are declaring these on one line, is:
FILE *from, *to;
This means "the expression *from
is type FILE
, and the expression *to
is type FILE
." And it looks like it, once you are used to this.
You could write this, but it's icky.
FILE* from, *to;
Yuck!
from
and to
are pointers, you cannot do any bitwise operation on them. However, <stdint.h>
provides intptr_t
which is of integer type and is guaranteed to hold a pointer, so casting your pointers to them first would be valid. However, this is ugly, so I would stick with the more readable version.
Bitwise operation are not allowed on pointers.
You should avoid such exercise.