int confusion = cabs(C++ - C);

Sent on Jun 06, 2001 

Even though C++ is a superset of C, there are subtle differences - both syntactic and semantic, between the two languages. Understanding these difference is crucial in understanding the problems associated with maintaining the compatibility and migration from C to C++ (In particular from ANSI C to ANSI C++).

In this newsletter lets explore few such differences between C and C++ through code examples. You are welcome to post more differences to get added to this list.

1) static i = 10;
const i = 10;
foo( ) { return 10;}
// implicit return type int assumed.

Implicit declarations default assumptions made by the compiler when type or relative information is missing. Implicit declarations are removed in C++, so you are required to give the types explicitly. Here implicit type of int is assumed in the declarations in C. Whereas in C++, this issues in error. Because implicit declarations are subtle source of confusion (and errors) and
reduces readability.


2) int *iptr = malloc(sizeof(int) * 100);

malloc() returns void * and it is common in C to assign like this with implicit conversion from void * to int * so valid in C. C++ is a strongly typed language. So such impliclit conversions from
are not allowed in C++. Again, this explicit casting makes programmers intention clearer and prevents unnecessary bugs due to implicit conversion.

3) int foo();
void *vp = (void *) foo;
A function can be assigned to a void * in C++ and this can't be done in C. So valid in C++ but not in C.

4) union { int i; float f; };
i = 10;
Anonymous unions supported in C++ but not in C. It means that the tag names are left out and it defines an unnamed object (not unnamed type).Note that usual member access is not required here; you can use as if it is an ordinary variable.

5) int main()
{
static int i;
if(i++==0)
main();
}
Calling main from within the program and recursively is valid in C but not in C++ (compiler will issue an error in that case). Calling main can create problems, because in C++, the constructors and destructors for the static members are available in the initialization and de-initialization routines and the main becomes as if it is declared
as:
int main()
{
__initializer(); // machine generated (logically)
// user given code for main() here
__deinitializer(); // machine generated (logically)
}
So problem occurs if the main can be called recursively. Moreover it doesn’t make much sense and little use for calling main recursively. So C++ disallows main to be called form anywhere from the program.

6) const int size = 10;
int array[size];
legal in C++ but not in C. Because consts can be used for specifying size of arrays in C++ (but not in C).

7) enum num {one,two};
printf("%d",sizeof(enum e));
In C the size of enumeration constant is sizeof(int) but not in C++. In C++ the size of the enumerated may be smaller or greater than sizeof(int). This is because the implementations may select the more appropriate size to represent the enumerated constants.

8) // this is in global area
int i;
int i=0;
This is called as tentative definitions in C, so is legal in C. Tentative definitions are not allowed in C++, so is illegal here. A tentative definition is a declaration that can become either a declaration or a definition. In the later parts of a program, if that variable is defined then that tentative definition becomes a declaration; else, it becomes a definition.
// this is in global area
int i;
// tentative definition.
// this becomes declaration after seeing the next definition
int i=0;  
// definition
ANSI C uses the presence or absence of an initializer to determine whether a declaration is a definition or an allusion. If no real definition is available up to the end of the file only one
definition for that variable is created and is initialized to zero.

9) const int i;
// error in C++. i has to be explicitly initialized.

All const variables that are not initialized will be automatically set to zero and the global const variables by default have external linkage. But in C++ all the const variables must be explicitly initialized and global const variables have static linkage.

10) register int ri;
int *rip = &ri;
Taking address of a register variable is legal in C++, but is illegal in C.

11) int main()
{
foo();
}
void foo()
{ }
Error in C++ but acceptable in C. In C++, functions are not forward referenced and function prototypes are a must, but optional in C.

12) char vowels[5] = "aeiou";
It is invalid in C++ but valid in C. Because, in C++ there should be enough space for NULL termination character in string constants.

      By mistake the programmer may have forgotten to give space for the NULL termination character. puts(vowels) will print up-to NULL termination that will be encountered somewhere else. Since the access is beyond the limit of character array this leads to undefined behavior. To prevent such problems this is flagged as an error in C++.

13) int i = 10;
(++i)++;
++i = 0;
Both are error in C but valid in C++. In C, applying prefix ++ operator yields an rvalue, but in C++ it yields an lvalue.

14) (sizeof(‘a’)==sizeof(char))?
printf("this is C++")
: printf("this is C")
The size of a character constant is the size of int in C. This is followed in C because int is the most efficient data-type that can be handled. But it wastes memory too. If the size of an integer is 4 bytes then the character constant also takes 4 bytes which is weird. In C++ size of a character constant is no more the size of int rather more naturally it is the size of character.

15) #ifdef __cplusplus
printf("this is C++");
#else
printf("this is C");
#endif

C++ compilers must define another preprocessor constant namely __cplusplus.

16) int fun();
int i = fun(10,20);
This is legal in C but invalid C++. In C it means fun() takes any number of arguments i.e. fun(...). But in C++ empty argument list means the function takes no arguments i.e. fun(void).

17) struct aStruct{ };
printf("%d", sizeof(struct aStruct));
This is error in C but valid in C++. ANSI C mandates atleast one member to be present in a structure, so this should issue an error in C. This is acceptable in case of C++; but an object should be associated with some memory and the object should be of size atleast 1; so the printf
may print the value 1 or a bigger number as the size of the structure.

18) struct someStruct{
typedef int INT;
INT i;
};
This is error in C but valid in C++. Because typedef is syntactically considered as a storage class and within the C structure definition, you cannot use any of the storage classes. But in C++, it is possible.


19) struct stu{
struct stuStu{
int someInt;
}someI;
};
struct stuStu ss;
Error in C++ but acceptable in C. This is because structures don’t introduce a new scope, it only introduces a namespace. Whereas in C++, classes introduces a scope (called class scope; but in C there is nothing called as struct scope), so the inner classes are not accessible
outside the class.

20) int x[99];
int f()
{
struct x { int a; };
sizeof(x);
}
This code is from [Ellis and Stroustrup 1995]. The sizeof in function f() prints the sizeof array in C and the size of the struct in C++. A structure name declared in an inner scope can hide the same name of an object, function, enumeration or type in an outer scope.

21) int foo(int i, int);
foo(2,3);
Acceptable in C++ and error in C. Unnamed function arguments are ignored in C++, but it is illegal in C. A more common example, but we seldom note, is in the case of overloading postfix ++ operator where we pass a dummy int argument to differentiate it from prefix ++.

So, if a code is given and asked the output, don't forget to ask if it is for C or C++. They differ considerably.

Yours Argumentatively,
Ganesh & Prakash.