Step 7 of 7
Where C and C++ differ
C++ grew out of C, and most C code is also valid C++. But the languages have been developed separately for decades, and some differences bite when you move code between them or mix them in one project.
| C | C++ | |
|---|---|---|
void * to another pointer |
converts automatically: int *p = malloc(n); |
needs a cast (or better, new, std::vector, std::make_unique) |
void f() |
"unspecified arguments" before C23; write void f(void) |
no arguments, same as f(void) |
struct Point |
the type is struct Point, unless you add a typedef |
the type is just Point |
sizeof('a') |
sizeof(int), usually 4: a character literal is an int |
1: it's a char |
variable-length arrays int a[n]; |
standard in C99, optional since C11 | not standard; GCC and Clang accept them as an extension (Clang warns) |
| designated initializers | any order, nested, and for arrays: {.y = 2, .x = 1}, [3] = 7 |
C++20, but only in declaration order and not for arrays (GCC rejects {.y = 2, .x = 1}, Clang warns) |
| string literal type | char[N] (writing to it is still undefined) |
const char[N] |
a const global |
visible to other files | private to its file unless marked extern |
bool, true, false |
from <stdbool.h> before C23, keywords since |
keywords |
new, class, delete, this |
ordinary names you can use for variables | reserved keywords |
#include <cstdlib>
#include <iostream>
struct Point {
int x;
int y;
};
int main() {
Point p{.x = 1, .y = 2}; // designators in declaration order
int* nums = static_cast<int*>(std::malloc(3 * sizeof(int))); // C++ needs the cast from void*
if (!nums) return 1;
nums[0] = p.x + p.y;
std::cout << sizeof('a') << " " << nums[0] << "\n"; // 1: a char literal is a char
std::free(nums);
}
1 3
Mixing C and C++ in one program
A C library can be used from C++ (the extern "C" section in the design patterns module shows how the headers make that work), and C++ can offer functions that C calls. What can't cross the boundary is C++-only machinery: classes with constructors, references, templates, overloading and exceptions. So libraries meant for both languages expose a plain C interface and use C++ inside.
In C++ code, prefer the C++ versions of C headers (<cstdlib>, <cstring>, <cstdio>), which put the names in namespace std, and prefer C++ facilities over C ones: std::string over char arrays, std::vector over malloc, streams or std::format over printf.
Your turn: this code was copied from a C project, and it doesn't compile as C++. Fix make_buffer so it compiles and works: Buffer's designated initializers must follow the declaration order, and malloc's result needs a cast. Keep free_buffer as it is.