C与C++的兼容性
在C中允许而在C++中不允许存在的代码语句

C++较C语言有更严格的类型转换和初始化规则 ， 因此一些在C语言里合法的语句在C++里是不合法的。ISO C++附录C.1中列出了这些区别。
一个常见的区别是在C语言中的指针类型更加弱类型。具体来说，C语言允许将void* 指针赋值给任何类型的指针而无需强制转换，而C++则不允许；这个习惯用法经常出现在使用malloc 管理内存的C代码中， 或POSIX线程库的上下文传递以及其他涉及回调的框架。例如，下面这个例子在C语言中是可行的，但在C++中不允许: void *ptr;
/*从void *到int *的隐式转换*/
int *i = ptr;
或类似的：int *j = malloc(5 * sizeof *j);     /*从void *到int *的隐式转换 */
为了使代码在C和C++中同时可用， 必须使用强制类型转换， 如下所示（然而这样在两种语言中都会报警告）：void *ptr;
int *i = (int *)ptr;
int *j = (int *)malloc(5 * sizeof *j);
C++中提供了其它方法来实现指针类型转换。C++不推荐继续使用老式类型转换。老式类型转换在形式上来说不是特别清晰，容易被忽略。。void *ptr;
auto i = reinterpret_cast<int *>(ptr);
auto j = new int[5];
C语言允许在安全的前提下隐式添加除const和volatile的关键字，而C++则不会。
C++为C语言的部分函数添加了一个参数带const的重载，例如strchr在C语言中的声明为char *strchr(char *)，而在C++中则有一个重载函数为const char *strchr(const char *)。
C++在枚举方面也更加严格。在C++中，int不能被隐式转换为枚举类型。因为在C++标准中并没有规定枚举的类型为int（在C语言标准中则规定了），并且大小可能与C++中int的大小不同。从C++11开始，C++允许程序员将自定义的整数类型赋值给枚举类型。
在C++中，const变量必须被初始化，但在C语言中不必：const int var1;
const int var2 = 1;
第一行代码在C语言中是允许的（在某些编译器中可能会报告“Warning”），但在C++中会报错；第二行代码在C和C++中都是合法的。
C++不允许goto和标签之间出现初始化语句。如下示例所示，该段代码在C语言中是允许的，但在C++中不允许。void fn(void)
{
    goto flack;
    int i = 1;
flack:
    ;
}
虽然语法上有效，但如果跳过的堆栈帧包含具有非平凡（nontrivial）析构函数的对象（即指针），则longjmp()函数会在C++中被认为是未定义的操作。 C++可以自由定义此时的行为，以便能够调用析构函数。但是，这样会使longjump()的一些用法失效， 否则就可以通过在单独的调用堆栈之间进行longjmp来实现线程或协程——在全局地址空间中从较低的调用堆栈跳转到较高的调用堆栈时，将析构函数用于较低调用堆栈中的每个对象。这个问题在C语言中不存在。
C语言中允许使用与用struct，enum和union类型名称相同的名称定义新结构体。enum BOOL {FALSE, TRUE};
typedef int BOOL;//在C语言中允许，在C++中不允许
在C语言中，由struct，enum或union创建的类型在声明变量时必须在自定义的类型前加struct，enum或union（取决于定义时的类型），而在C++中不必。因为自定义类型在创建时已隐含typedef（这也是上一点区别形成的原因）。struct foo{
        int bar;
};
/*
在C++中，以上形式被隐式转换为：
typedef struct foo{
        int bar;
} foo;
*/
struct foo foobar;//在C与C++中均可
foo foobar2; //在C语言中不允许，在C++中允许
在C++中不允许使用旧式K&R声明（如下所示），这种声明在C语言中仍然可用，但是标准已将这种声明方式列为「过时」（「过时」是在ISO C标准中定义的术语，它表示委员会可以考虑在未来的标准中将其删除）。int add(a,b)
int a;
int b;
{
    return a+b;
}
在C99标准出现之前，C语言允许隐式函数声明（即省略函数声明），而C++不允许；但在C99标准出现及以后，C与C++均不允许使用这种形式。
在C语言中，如果函数原型中没有参数（如int foo();，表明该函数的参数不确定（这是一种标准不推荐的用法）；而在C++中相同的形式等同于int foo(void);。如果想要在C语言中表示没有参数，应该使用int foo(void);。
在C和C++中，都可以嵌套定义struct类型，如下所示：struct foo{
    struct bar{
        int x;
    };
    int y;
}
然而，在使用时，C和C++采用不同的方法，假设此时已有struct foo类型变量a， 且x = 1，y = 2；如要将x赋值给变量b，c：//以下是C语言方法,在C++中不允许：
int b = a.x;

//以下是C++特有方法，在C中不允许:
int c = a::x
C99和C11添加了一些未包含在标准C++中的附加功能，例如复数，变长数组（值得注意的是，在C99中列为强制要求的VLA（变长数组）和复数在C11中被列为了可选项，这是由于部分特殊平台的C编译器无法有效率地实现或无法实现这两个功能导致的。目前基本所有平台都有对应的可使用VLA的编译器），灵活数组类型（Flexible array member，也叫伸缩型数组成员），restrict关键字，数组参数限定词，复合文字（英语：），指定初始化项目，可变参数宏，附加数学库，预定义的标识符（如__func__)和可移植整数类型。
C99中通过内建的关键字_Complex和由它定义的宏complex实现了虚数类型——float complex和double complex；而C++通过一种完全不同的方式实现了它——使用虚数库。这两种方式是不兼容的。
VLA可能导致sizeof的值在运行时才能确定。void foo(size_t x, int a[*]);  // 使用VLA的函数
void foo(size_t x, int a[x]) 
{
    printf("%zu\n", sizeof a); // 等同于sizeof(int*)
    char s[x*2];
    printf("%zu\n", sizeof s); // 将显示x*2
}
在C99中，如果一个结构体有多个变量且它的最后一个变量为数组，则它可以是一个柔性数组。它与VLA类似，但VLA不能出现在定义中。它不指定数组的长度。截止到C++20，C++中没有类似的功能。下面是它的一个例子：struct X
{
    int n, m;
    char bytes[];
}
截止到C++20标准，restrict类型限定符并没有出现在C++里；但是很多编译器都提供了对它的支持（如GCC，MSVC，ICC，Clang等）。
函数声明中的数组类型限定符在C++中是不允许的，下面是一个例子：int foo(int a[const]);     // 相当于int foo(int *const a);
int bar(char s[static 5]); // 表示s的长度至少为5
C中的复合文字特性在C++中以一种叫做“列表初始化”的方法被实现——虽然它们在意义和作用上是不同的，但它们通常能起到相同的效果。struct X a = (struct X){4, 6};  // 在C++ 中等于 X{4, 6}.
从C99开始，C语言支持结构的指定值初始化；在C++20以前，这是不允许的；但是从C++20标准开始，C++也支持了这个特性。struct X a = {.n = 4, .m = 6};  
char s[20] = {[0] = 'a', [8]='g'};
在C++中，可以使用“noreturn”来标记一个没有返回值的函数，但在C11以前没有这样一个关键字。在C11中新增了关键字“_Noreturn”。
C语言允许在函数原型中声明复合数据类型，而C++不允许。
C++较C语言增加了一些关键字，这使得如果一段C语言代码使用了C++中新增的关键字作为标识符，它将会是非法的。struct template 
{
    int new;
    struct template* class;
};
以上代码在C语言中是允许的，但是在C++中不允许。