Programming C++  «Prev  Next»
Lesson 5 Differences in C and C++ program structure
Objective Program Structure Differences between C and C++.

Differences in C and C++ Programs

While there are some similarities between the structure of C and C++ programs, there are also some crucial differences.
  1. C++ relies on an external standard library to provide assertion testing. The information the program needs to use this library resides in the library file assert.h. The assert macro tests a condition for correctness and terminates the program if the test fails.
  2. A C++ program consists of declarations that may be in different files. Each function is on the external, or global, level and may not be declared in a nested manner. The files act as modules and may be separately compiled. We will be discussing scope and storage classes in greater detail later in this course.

C++ was based on C and retains a great deal of the functionality. C++ does not retain complete source-level compatibility with C. There are a few anomalies for C++ programmers trying to write C code, and C programmers trying to compile with a C++ compiler.

Implicit Assignment from void*

Question: Can you implicitly assign from a void* type to any other type in C++?
No, in C++, you cannot implicitly assign from a void* to any other pointer type. The C++ language is more strict than C when it comes to type safety, and this is evident in the handling of void pointers. In C, a void* pointer can be implicitly cast to any other pointer type. However, in C++, an explicit cast is required to convert a void* to another pointer type.
Here is an example illustrating this difference:
void* v_ptr;
int* i_ptr;

// In C, this is allowed.
// In C++, this would generate a compile error.
i_ptr = v_ptr;  

// In both C and C++, this is allowed.
i_ptr = (int*)v_ptr; 

In the above example, the assignment i_ptr = v_ptr; would be acceptable in C, but in C++, it would generate a compile-time error. To make this assignment in C++, an explicit cast is required, as in i_ptr = (int*)v_ptr;. This stricter requirement in C++ helps to prevent errors that could occur due to incorrect assumptions about the type of data being pointed to by a void pointer. It reflects the overall philosophy of C++ to provide stronger type checking than C, to reduce the possibility of programmer errors. Note: Even though C++ allows you to cast a void* to any other pointer type, it's generally a good practice to avoid this unless absolutely necessary. The reason is that such a cast bypasses the type system, possibly leading to subtle bugs. Whenever possible, it's better to use safe and well-defined conversions and casts.
You cannot implicitly assign from a void* to any other type. For instance, the following is perfectly valid in C (in fact, it's arguably the preferable way of doing it in C)

int *x = malloc(sizeof(int) * 10);

but it will not compile in C++.
The explanation from Bjarne Stroustrup himself is that this is not type safe. What this means is that you can have a void* that points to anything at all, and if you then assign the address stored in that void* to another pointer of a different type, there is not any warning at all about it.
Consider the following:
int an_int;
void *void_pointer = &an_int;
double *double_ptr = void_pointer;
*double_ptr = 5;

When you assign *double_ptr the value 5, it's writing 8 bytes of memory, but the integer variable an_int is only 4 bytes. Forcing a cast from a void pointer makes the programmer pay attention to these things.