What is the difference between C, C++ and C#?
Contrary to the way it looks, C is what I'd call an "expression-oriented" language, with some imperative and (minimally) declarative elements layered on top. Imperative elements govern control flow. Expression elements mostly deal with computation, though the ?: operator governs control flow, along with giving a result. Structs/unions, along with bitfields, are a declarative feature that allow the programmer to create offsets inside a defined area of memory, and/or create types which allow the program to allocate more areas of memory, which can be navigated by offsets.
C++ layers declarative syntax on top of the aforementioned features of C, to define an extra layer of scope for functions, with parameterized typing, called "classes." It greatly expands upon the concept of the struct in C, by attaching strong typing to functions (the types of which can be parameterized), and heap allocations (which can also be parameterized), and adding an implied "this" pointer to functions that are associated with structured data. Other features include:
A table of pointers inside of these expanded structs, which may exist inside of heap allocations, to functions that are defined in derived classes, to enable "downward" polymorphism, when functions associated with structured data are called.
A new type of reference called an "alias." I might call it a "roving variable." Like a pointer, it can be made to reference different areas of memory, but like a variable, it can be used to assign rvalues of its type to memory locations without the need to explicitly dereference it. An alias doesn't function like a variable by itself. It needs a defined address space (a declared variable, or defined structure of some sort, that is known to it) in order to function as a variable.
A designator called "const" that allows values to be assigned to variables once, but not modified.
A meta-structural feature called "templates" that allows types to be parameterized (these types are filled in when the source is compiled).
A little bit of meta-programming, where during run-time some information can become known about the type of an object.
Lambdas were recently added to C++. From what I understand, these are functions that are defined inline, and use an abbreviated syntax.
Like with C, C++ takes a layered approach to these different aspects. As a result, C++ does not necessarily warn you if you do something like an assignment inside of a conditional test expression.
C# adopted some syntactic features of C++, but it doesn't compile and run the way C++ does. C# holds your hand more than C++ does. It doesn't allow certain expressions to be used inside of certain constructs (like an assignment inside a test condition), as some things are considered bad form, and probably a mistake.
Like with C++, what C# calls classes are an expansion on the struct concept from C, but there are no pointers in C# code, unless you explicitly go into "native" mode. I forget how this is done, but it is possible to go down to the machine level, inside a "confined" space, inside a C# program. The runtime keeps the pointers, and hands references to them to the running code. This is to enable garbage collection, which C++ doesn't have.
A consequence of this is that deallocating memory is explicitly deterministic in C++, but it's not in C#. Memory is made available for garbage collection in C# when a variable no longer refers to a value or object, but when that memory is deallocated and cleared is determined by the runtime. In C++, memory can only be deallocated explicitly, using a "delete" command.
C# has two types of variables: "value" and "object." Variables of object type are stored on the heap. Value type variables are not. Value type variables behave rather like "native" variables in C++ (types like "int"), except that they are classes, and the values that are assigned to them are classes or structs. The way you can tell the difference between the two is that value type variables can take a literal. You can say:
int a = 10;
Variables of object type have to receive an object that was brought into existence by the "new" operator, which allocates the object on the heap. This behavior will be familiar to C++ programmers.
It is possible to convert between the two types of variables, doing what's called "boxing" and "unboxing." In C++ this would be accomplished through explicit or implicit cast operators.
Variables of object type function rather like aliases in C++, except they don't need a defined address space. They just refer to objects in memory (or null, if they refer to nothing). There is some "magic" under the covers about how the runtime stores these values, and arrives at the stored values (when retrieving them), since again, there are no pointers. Objects are just bound to object variables. The programmer is not supposed to concern themselves with how. There is no relationship between a variable of object type and where an object is stored in memory. To make another analogy, object variables function rather like keys in a hash table, referring to objects that are stored along with the keys.
Object variables can be re-assigned to different pieces of memory by reassigning them to different objects, though the runtime arranges what memory is accessed. The programmer has no explicit control over that. All the programmer knows is that a variable may be referencing something else when s/he reassigns a variable to another object.
Similar to C++, in C# you define functions that are associated with structured data, though unlike C++, you cannot define free-standing functions that are not associated with a class.
C# implements the same basic polymorphic function logic within objects as C++ does, though how it does it I don't think is made known to programmers.
Generics were eventually added to the language, which are analogous to templates in C++. They allow types to be parameterized.
C# has lambdas, which can function like closures, like C++'s recent addition of lambdas. Before .Net got lambdas, Microsoft introduced anonymous functions, which functioned like lambdas, but were more verbose, and were generally used to handle event logic.
In more recent versions of C# it has been possible to extend class definitions, so that programmers who use a framework can add methods to an existing class without having to create a derived class, modifying the original source code, or re-compiling it. C++ has not had this capability.
C# modules (DLLs) can be called up by version number. I haven't heard of any implementation of C++ that has that capability.
C# modules can be incrementally downloaded over the internet and late-bound into a running program, as needed. C/C++ hasn't had that ability in their runtimes, except via. binary DLLs in Windows, or .so libraries in Unix (or some equivalent on Linux). In C/C++ it's done through OS calls. In .Net it's done through calls to the Framework's library.
From what I've understood, C has been more portable between platforms than C++ (though perhaps this has improved since I last used C++, which was in 2006). C# doesn't have much portability. If you want to use the most up-to-date version of C#, you have to use it on a version of Windows (with one exception, which I talk about below). If you're able to skimp on the version, there is an open source implementation of the .Net runtime called Mono that runs on multiple platforms, with its own C# compiler. It is able to emulate Windows GUI functions in client apps.
Microsoft has had a project going for years now called "Silverlight" that brings .Net into the browser, and from what I remember, C# is compatible with it. Silverlight runs on multiple browsers, on Windows and Mac. I vaguely remember that it runs on Linux as well.
From what I've understood, the only browser that runs C++ code is the Google Chrome browser, in what's called "native client."
I forget exactly when this happened (I'm thinking mid-2000's). Microsoft introduced Managed C++, an implementation of the language that can run using managed memory in the .Net runtime. I looked at the first version, and it was more verbose than native C++. I think they've cleaned up the syntax since then. Like with C#, it had "value" and "object" type variables, and you had to specify these explicitly (you could not use '*' to declare "object" variables. Instead you used a "ref" designator. However, you used "->" to refer to managed fields and methods). What's unique about Managed C++ is that you can mix native C++ code with managed code rather seamlessly, and it's possible to transfer values from native C++ code into managed memory, and thereby access them from managed code.
Another unique feature of Managed C++ was that it was (at one time, I don't know if they still allow this) possible to get an address to managed memory, and to go through it, and modify memory, using a native pointer type, just as you could in native C++. This, of course, was considered dangerous, as it would allow a sloppy programmer to corrupt managed memory. But it was possible.
Contrary to the way it looks, C is what I'd call an "expression-oriented" language, with some imperative and (minimally) declarative elements layered on top. Imperative elements govern control flow. Expression elements mostly deal with computation, though the ?: operator governs control flow, along with giving a result. Structs/unions, along with bitfields, are a declarative feature that allow the programmer to create offsets inside a defined area of memory, and/or create types which allow the program to allocate more areas of memory, which can be navigated by offsets.
C++ layers declarative syntax on top of the aforementioned features of C, to define an extra layer of scope for functions, with parameterized typing, called "classes." It greatly expands upon the concept of the struct in C, by attaching strong typing to functions (the types of which can be parameterized), and heap allocations (which can also be parameterized), and adding an implied "this" pointer to functions that are associated with structured data. Other features include:
A table of pointers inside of these expanded structs, which may exist inside of heap allocations, to functions that are defined in derived classes, to enable "downward" polymorphism, when functions associated with structured data are called.
A new type of reference called an "alias." I might call it a "roving variable." Like a pointer, it can be made to reference different areas of memory, but like a variable, it can be used to assign rvalues of its type to memory locations without the need to explicitly dereference it. An alias doesn't function like a variable by itself. It needs a defined address space (a declared variable, or defined structure of some sort, that is known to it) in order to function as a variable.
A designator called "const" that allows values to be assigned to variables once, but not modified.
A meta-structural feature called "templates" that allows types to be parameterized (these types are filled in when the source is compiled).
A little bit of meta-programming, where during run-time some information can become known about the type of an object.
Lambdas were recently added to C++. From what I understand, these are functions that are defined inline, and use an abbreviated syntax.
Like with C, C++ takes a layered approach to these different aspects. As a result, C++ does not necessarily warn you if you do something like an assignment inside of a conditional test expression.
C# adopted some syntactic features of C++, but it doesn't compile and run the way C++ does. C# holds your hand more than C++ does. It doesn't allow certain expressions to be used inside of certain constructs (like an assignment inside a test condition), as some things are considered bad form, and probably a mistake.
Like with C++, what C# calls classes are an expansion on the struct concept from C, but there are no pointers in C# code, unless you explicitly go into "native" mode. I forget how this is done, but it is possible to go down to the machine level, inside a "confined" space, inside a C# program. The runtime keeps the pointers, and hands references to them to the running code. This is to enable garbage collection, which C++ doesn't have.
A consequence of this is that deallocating memory is explicitly deterministic in C++, but it's not in C#. Memory is made available for garbage collection in C# when a variable no longer refers to a value or object, but when that memory is deallocated and cleared is determined by the runtime. In C++, memory can only be deallocated explicitly, using a "delete" command.
C# has two types of variables: "value" and "object." Variables of object type are stored on the heap. Value type variables are not. Value type variables behave rather like "native" variables in C++ (types like "int"), except that they are classes, and the values that are assigned to them are classes or structs. The way you can tell the difference between the two is that value type variables can take a literal. You can say:
int a = 10;
Variables of object type have to receive an object that was brought into existence by the "new" operator, which allocates the object on the heap. This behavior will be familiar to C++ programmers.
It is possible to convert between the two types of variables, doing what's called "boxing" and "unboxing." In C++ this would be accomplished through explicit or implicit cast operators.
Variables of object type function rather like aliases in C++, except they don't need a defined address space. They just refer to objects in memory (or null, if they refer to nothing). There is some "magic" under the covers about how the runtime stores these values, and arrives at the stored values (when retrieving them), since again, there are no pointers. Objects are just bound to object variables. The programmer is not supposed to concern themselves with how. There is no relationship between a variable of object type and where an object is stored in memory. To make another analogy, object variables function rather like keys in a hash table, referring to objects that are stored along with the keys.
Object variables can be re-assigned to different pieces of memory by reassigning them to different objects, though the runtime arranges what memory is accessed. The programmer has no explicit control over that. All the programmer knows is that a variable may be referencing something else when s/he reassigns a variable to another object.
Similar to C++, in C# you define functions that are associated with structured data, though unlike C++, you cannot define free-standing functions that are not associated with a class.
C# implements the same basic polymorphic function logic within objects as C++ does, though how it does it I don't think is made known to programmers.
Generics were eventually added to the language, which are analogous to templates in C++. They allow types to be parameterized.
C# has lambdas, which can function like closures, like C++'s recent addition of lambdas. Before .Net got lambdas, Microsoft introduced anonymous functions, which functioned like lambdas, but were more verbose, and were generally used to handle event logic.
In more recent versions of C# it has been possible to extend class definitions, so that programmers who use a framework can add methods to an existing class without having to create a derived class, modifying the original source code, or re-compiling it. C++ has not had this capability.
C# modules (DLLs) can be called up by version number. I haven't heard of any implementation of C++ that has that capability.
C# modules can be incrementally downloaded over the internet and late-bound into a running program, as needed. C/C++ hasn't had that ability in their runtimes, except via. binary DLLs in Windows, or .so libraries in Unix (or some equivalent on Linux). In C/C++ it's done through OS calls. In .Net it's done through calls to the Framework's library.
From what I've understood, C has been more portable between platforms than C++ (though perhaps this has improved since I last used C++, which was in 2006). C# doesn't have much portability. If you want to use the most up-to-date version of C#, you have to use it on a version of Windows (with one exception, which I talk about below). If you're able to skimp on the version, there is an open source implementation of the .Net runtime called Mono that runs on multiple platforms, with its own C# compiler. It is able to emulate Windows GUI functions in client apps.
Microsoft has had a project going for years now called "Silverlight" that brings .Net into the browser, and from what I remember, C# is compatible with it. Silverlight runs on multiple browsers, on Windows and Mac. I vaguely remember that it runs on Linux as well.
From what I've understood, the only browser that runs C++ code is the Google Chrome browser, in what's called "native client."
I forget exactly when this happened (I'm thinking mid-2000's). Microsoft introduced Managed C++, an implementation of the language that can run using managed memory in the .Net runtime. I looked at the first version, and it was more verbose than native C++. I think they've cleaned up the syntax since then. Like with C#, it had "value" and "object" type variables, and you had to specify these explicitly (you could not use '*' to declare "object" variables. Instead you used a "ref" designator. However, you used "->" to refer to managed fields and methods). What's unique about Managed C++ is that you can mix native C++ code with managed code rather seamlessly, and it's possible to transfer values from native C++ code into managed memory, and thereby access them from managed code.
Another unique feature of Managed C++ was that it was (at one time, I don't know if they still allow this) possible to get an address to managed memory, and to go through it, and modify memory, using a native pointer type, just as you could in native C++. This, of course, was considered dangerous, as it would allow a sloppy programmer to corrupt managed memory. But it was possible.
0 comments:
Post a Comment