I was reading through the questions with most votes from the history tag and came across https://stackoverflow.com/q/4377512/627005, where the accepted answer states that C has "minimal type safety", C++ has "better type safety" and C# "has type safety". Why is C# more type safe than C++?
C++ is a superset of C, so both languages have similar syntax, code structure, and compilation. Almost all of C's keywords and operators are used in C++ and do the same thing. C and C++ both use the top-down execution flow and allow procedural and functional programming.
Compared to C, C++ has significantly more libraries and functions to use. If you're working with complex software, C++ is a better fit because you have more libraries to rely on. Thinking practically, having knowledge of C++ is often a requirement for a variety of programming roles.
C++ inherits lots of C features, so you can always do something unsafe if you want to. It's only that if you use C++ idiomatically, then you'll usually get type safety. There's just nothing that will categorically stop you if you choose to go off the safe grounds.
C# enforces a stronger type system and restricts the use of C-style constructions (most notably pointer arithmetic) to marked "unsafe" regions, so you have better (= automated) control over what is typesafe and what isn't.
Digression: It may be worthwhile to reflect a bit on what "safe" means. A language is called safe if we can verify that a particular piece of code is correct. In a statically typed language, this basically boils down to type checking: If we have an expression a + b
, then we just check the types: int
plus int
equals int
, fine; struct
plus union
makes no sense, compile error.
The odd man out in this setup is the dereference operator *
: When we see *p
, we can check that p
is a pointer, but that is not sufficient to prove that the expression is correct! The correctness of the code does not only depend on the type of p
, but also on its value. This is at the heart of the un-safety of C and C++.
Here are two examples to illustrate:
// Example #1
void print_two(const char * fmt)
{
double d = 1.5;
unsigned int n = 111;
printf(fmt, d, n);
}
// Example #2
unsigned int get_int(const char * p)
{
return *(unsigned int *)(p - 3);
}
In Example #1, the correctness of the code depends on the run-time supplied value of the string pointed to by fmt
. In Example #2, we have the following:
unsigned int n = 5;
double d = 1.5;
const char * s = "Hello world";
get_int((char*)(&n) + 3); // Fine
get_int((char*)(&d) + 3); // Undefined Behaviour!
get_int(s + 5); // Undefined Behaviour!
Again, just by looking at the code of get_int()
, we cannot tell whether the program will be correct or not. It depends on how the function is used.
A safe language will not allow you to write such functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With