In a weakly-typed language, type-casting exists to remove ambiguity in typed operations, when otherwise the compiler/interpreter would use order or other rules to make an assumption of which operation to use.
Normally I would say PHP follows this pattern, but of the cases I've checked, PHP has behaved counter-intuitively in each.
Here are those cases, using JavaScript as a comparison language.
String Concatentation
Obviously this is not a problem in PHP because there are separate string concatenation (.
) and addition (+
) operators.
JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15
String Comparison
Often in computer systems "5" is greater than "10" because it doesn't interpret it as a number. Not so in PHP, which, even if both are strings, realizes they are numbers and removes the need for a cast):
JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false"; // false!
Function signature typing
PHP implements a bare-bones type-checking on function signatures, but unfortunately it's so flawed it's probably rarely usable.
I thought I might be doing something wrong, but a comment on the docs confirms that built-in types other than array cannot be used in PHP function signatures - though the error message is misleading.
PHP
function testprint(string $a) {
echo $a;
}
$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
// must be an instance of string, string given" WTF?
And unlike any other language I know, even if you use a type it understands, null can no longer be passed to that argument (must be an instance of array, null given
). How stupid.
Boolean interpretation
[Edit]: This one is new. I thought of another case, and again the logic is reversed from JavaScript.
JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.
So in conclusion, the only useful case I can think of is... (drumroll)
Type truncation
In other words, when you have a value of one type (say string) and you want to interpret it as another type (int) and you want to force it to become one of the valid set of values in that type:
$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties
I can't see what upcasting (to a type that encompasses more values) would really ever gain you.
So while I disagree with your proposed use of typing (you essentially are proposing static typing, but with the ambiguity that only if it was force-cast into a type would it throw an error — which would cause confusion), I think it's a good question, because apparently casting has very little purpose in PHP.
A point that most of the answers here are not addressing, at least not explicitly, is that a null pointer is a value that exists during execution, and a null pointer constant is a syntactic construct that exists in C source code.
A null pointer constant, as Karlson's answer correctly states, is either an integer constant expression with the value 0 (a simple 0
is the most common example), or such an expression cast to void*
(such as (void*)0
).
NULL
is a macro, defined in <stddef.h>
and several other standard headers, that expands to an implementation-defined null pointer constant. The expansion is typically either 0
or ((void*)0)
(the outer parentheses are needed to satisfy other language rules).
So a literal 0
, when used in a context that requires an expression of pointer type, always evaluates to a null pointer, i.e., a unique pointer value that points to no object. That does not imply anything about the representation of a null pointer. Null pointers are very commonly represented as all-bits-zero, but they can be represented as anything. But even if a null pointer is represented as 0xDEADBEEF
, 0
or (void*)0
is still a null pointer constant.
This answer to the question on stackoverflow covers this well.
This implies, among other things, that memset()
or calloc()
, which can set a region of memory to all-bits-zero, will not necessarily set any pointers in that region to null pointers. They're likely to do so on most implementations, perhaps even all existing ones, but the language doesn't guarantee it.
This question is really a duplicate of this one, but Stack Exchange doesn't allow marking duplicates across sites.
Best Answer
A typical use case (in hosted user-code applications) to cast some pointer to an
intptr_t
(from<stdint.h>
standard C99 or C11 header) is to compute some hash code on that pointer:For historical reasons (i.e. Linux came before C99), the Linux kernel uses
unsigned long
instead ofuintptr_t
(the unsigned integral type of the samesizeof
as pointers) orintptr_t
Also, user-space to kernel-space transmissions (e.g. arguments of syscalls) is in the Linux kernel in terms of
long
orunsigned long
(again, you'll better think in term ofintptr_t
oruintptr_t
). Even when you transmit addresses from user-space to kernel-space, you need to think about address spaces and virtual memory (and it is becoming complex, since user-space and kernel-code live in different address spaces).A quote on the topic from LDD3:
Note that the Linux kernel is not coded in hosted academically standard portable C99. It is a freestanding program, coded with a few particular C compilers in mind (GCC and perhaps also in the future Clang/LLVM...).
The Linux kernel is using some GCC extensions to C (e.g.
__attribute__
-s, builtins, computed goto-s, etc...), perhaps wrapped with macros. Most of these extensions are also supported by Clang / LLVM.Kernel newbies & lkml are probably good places to ask about that.