"The C Programming Language: A new language which combines the flexibility of assembly language with the power of assembly language." -- Murphy's Introduction to C
Comments
In C, we only had block comments. In C++, we also have "to end of line" comments. An example will demonstrate:The C++-style comments will include everything from the // (which is a single token much like the ++ operator) to the end of the line. So, we will still need the orginal and more flexible /* ... */ comment syntax.int main(void) { /* This is a block comment. Ok in C and C++ */ /* This is also a block comment. Ok in C and C++ */ // This is a C++ style comment. // This type of comment may not work in all C compilers. }
int fn1(int a /* a should be positive */, int b /* b can't be 0 */);
Strictly speaking, the // comment character is illegal in a C program. However, many C compilers have been extended to accept both types of comments. (Microsoft has been accepting it since version 6.0 of the DOS version of C, which is about 1989. Yeah, they started over again at 1.0 with "Visual" C++ and there never was a version 3. But I digress...)
Function Prototypes
In C, if the compiler encountered a function call before seeing the function declaration or definition, it would assume certain things about the function:In C, the above program will compile "fine". Of course, it won't link. In C++, you will get an error (not a warning):void fn2(void) { /* Undeclared function, assumes it takes int,double and returns an int */ SomeFunction(1, 3.0); }
You must prototype every function in your program:error: 'SomeFunction' undeclared (first use this function)
// Function prototype required in C++ int SomeFunction(int, double); void fn2(void) { // Compiles just fine now SomeFunction(1, 3.0); }
void Parameter Lists
In C, a function is allowed to not specify any parameters in its parameter list:This means that the function can take any number and type of arguments. This was simply because the earliest versions of C didn't require the programmer to declare them. (This turned out to be a disaster and later versions of C "encouraged" function prototypes so the compiler could check for bad behavior.) If a function truly does not take any arguments, then the void keyword is used to indicate this fact:int foo();
Realize that these two functions are NOT the same in C:int foo(void);
Accepts any number/type of arguments | Accepts no arguments | |
---|---|---|
int foo(); |
int foo(void); |
Printing to stdout
There are more ways to print in C++.C++ example:#include <stdio.h> int main(void) { printf("C programming "); printf("is fun.\n"); return 0; }
We will look at cout (and the input version, cin) in more detail later.#include <iostream> // Notice the missing .h in the filename int main() { std::cout << "C++ programming "; std::cout << "is more fun." << std::endl; return 0; }
Variable Declarations
In C, all variables must be declared at the top of a scope. In C++, this is relaxed to allow you to declare new variables closer to their actual use.#include <stdio.h> /* printf */
int main(void)
{
int a; /* declaration */
int b = 3; /* initialization (declaration + assignment) */
double c = foo(2); /* initialization (declaration + assignment) */
int x; /* OK, declaration */
a = b * 2; /* assignment/multiply (no declaration) */
/* In C, no more declarations allowed in this scope */
c = 3.1415926; /* assignment, no declaration */
printf("%f\n", c); /* function call, no declaration */
int d = 7; /* error in C, OK in C++ */
int e; /* error in C, OK in C++ */
x = 5 * c; /* OK, no declaration */
return x;
}
This also allows you the convenience of declaring the index of a for loop precisely
where you need it. In C, this is the formal syntax for the for loop:
In C++, there is a slight (but important) difference:for ( <expression1>; <expression2>; <expression3> ) <statement>
This is what allows you to declare the index variable as part of the loop in C++:for ( <init-statement>; <expression>; <expression> ) <statement>
Each of the two i variables are different. (Different scopes)int a[10]; /* i doesn't exist here */ for (int i = 0; i < 10; i++) a[i] = i; /* i doesn't exist here */ for (int i = 0; i < 10; i++) a[i] = i * i; /* i doesn't exist here */
You have to watch out and not do this:
The error message from the GNU C++ compiler:int a[10]; for (int i = 0; i < 10; i++) a[i] = i; /* ERROR: i is undefined */ for (i = 0; i < 10; i++) a[i] = i * i;
Fortunately, most (all?) compilers today will give you an error if you do that, though. The reason the compiler doesn't just say that i is undefined is because this is how C++ used to work. The compiler is just trying to remind you that the behavior of the for statement has changed.main.cpp:28: error: name lookup of `i' changed for new ISO `for' scoping main.cpp:25: error: using obsolete binding at `i'
If you want to use the index variable from the for loop outside of the loop, you have to declare it outside of the loop:
int a[10]; int i; /* i is in scope */ for (i = 0; i < 10; i++) a[i] = i; /* i is in scope */ for (i = 0; i < 10; i++) a[i] = i * i; /* The i on the next line is a new variable that exists only in the loop */ for (int i = 0; i < 5; i++) a[i] = i * i; /* i (from line 2 above) is in scope with value 10 */ printf("The value of i is %i\n", i);
The literal char data type
In C, the type of a literal char is actually int. In C++, the type is char:
CThis only applies to literal characters, i.e., constants in single-quotes. Constants and variables of type char are actually char in both languages:Output:printf("sizeof('A') is %lu\n", sizeof('A'));C++sizeof('A') is 4Output:std::cout << "sizeof('A') is " << sizeof('A') << std::endl;sizeof('A') is 1
COutput:char c; printf("sizeof(c) is %lu\n", sizeof(c));C++sizeof(c) is 1Output:char c; std::cout << "sizeof(c) is " << sizeof(c) << std::endl;sizeof(c) is 1
The const keyword
In C, const is not the same kind of constant as in C++, which means that you couldn't use it to specify the size of a static array in C:You have to use the #define preprocessor directive:const int SIZE = 10; // constant? int array[SIZE]; // compile error, variable sized array
In C++, the first example above works as expected.#define SIZE 10 // SIZE is an alias for 10 int array[SIZE]; // OK, compiler replaces SIZE with 10
There is another subtle difference between C and C++ with respect to the const keyword. In C++, declaring a global variable const gives it internal linkage instead of external linkage. Here's an example:
Compiling the .c files with a C compiler:
file1.c file2.c #include <stdio.h> const int foo = 1; void fn(void); int main(void) { fn(); printf("foo is %i\n", foo); return 0; } #include <stdio.h> const int foo = 2; void fn(void) { printf("foo is %i\n", foo); }
gcc file1.c file2.c
How would you answer the above questions now?g++ file1.c file2.c
The real power of this feature is that you can put constants in header files in C++. This is something that can't be done in C (due to the One Definition Rule), which is why we were always using #define instead of const.
The bool Type
/* Define our own boolean type and values */
#define BOOL int
#define FALSE 0
#define TRUE 1
BOOL BitIsSet(int value, int position)
{
if (value & (1 << position))
return TRUE;
else
return FALSE;
}
void f(void)
{
BOOL b = BitIsSet(7, 2); /* b is a BOOL */
int x = BitIsSet(7, 2); /* OK, no type-checking error (BOOL is int) */
BOOL c = 42; /* OK, no type-checking error (BOOL is int) */
/* BOOL is just an int, so the expression evaluates to an integer */
if (BitIsSet(7, 2))
printf("Bit 2 of integer 7 is set\n");
/* Prints: b is 1, c is 42, x is 1 */
printf("b is %i, c is %i, x is %i\n", b, c, x);
}
In C++, we have a built-in bool type (and true/false):
bool BitIsSet(int value, int position)
{
if (value & (1 << position))
return true;
else
return false;
}
void f(void)
{
bool b = BitIsSet(7, 2); // b is a real bool
int x = BitIsSet(7, 2); // OK, converting bool to int
bool c = 42; // Possible warning: truncating
// int to bool (c is true, 1 as int)
// Expression evaluates to a bool
if (BitIsSet(7, 2))
printf("Bit 2 of integer 7 is set\n");
// Prints: b is 1, c is 1, x is 1
printf("b is %i, c is %i, x is %i\n", b, c, x);
}
There are some obvious issues here:
The Definition of NULL
In C, NULL is a void pointer and is usually defined as:In C++, NULL is an integer and is defined as:#define NULL ((void *)0)
These two definitions are not the same (integer vs. void pointer) and, depending on the circumstances, may cause compiler warnings or strange behavior.#define NULL 0
With most compilers' header files, you'll see something like this (from stdio.h):
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
In practice, this is generally not a problem.
The C++11 specification provides a new keyword, nullptr, that can be used to unambiguously refer to the NULL pointer, however it may be represented. We will look at this later.
Structure tags
Recall the general form of a structure declaration:In C, when we created an instance of a structure, we were required to use the struct keyword: Create a structure named TIME, (no space is allocated):struct tag { members }variable-list;
Create two variables of type struct TIME, (space is allocated):struct TIME { int hours; int minutes; int seconds; };
We could use the typedef keyword:struct TIME t1, t2; /* You need the struct keyword in C*/
In C++, when you define a structure with the struct keyword, you are creating a new type:typedef struct /* use typedef keyword to create a new type */ { int hours; int minutes; int seconds; }TIME; /* TIME is a type, not a variable */ TIME t1, t2; /* Don't need the struct keyword now */
struct TIME { int hours; int minutes; int seconds; };
TIME t1, t2; // TIME is a new type, so you don't need the struct keyword