产生这一问题的原因是:微软开发的MSVC编译器(cl.exe)本质上是一个C++语言编译器,编译C语言源程序只是它的一个附属功能。有一些C语言中的标准库函数在C++中几乎不使用,微软从MSVC 2005开始就会将这些函数标记为“弃用”【微软并没有在C运行时库中移除这些函数的实现,只是在函数声明中加了一个微软自己定义的“弃用”属性】,并在编译时给出警告信息(新版本会给出错误信息),这个警告/错误的代码就是C4996。
例如:输入数据时,C++使用的是
int a;
std::cin >> a;
而不是C语言中的:
int a;
scanf ("%d", &a);
所以微软就会在C++的编译过程中弃用scanf函数。
又例如:C++有字符串类型,可以直接进行字符串变量之间的赋值操作:
std::string str1 {"Hello, world!"}, str2;
str2 = str1;
以上代码可以直接将str1的值赋给str2。然而C语言没有字符串类型,只能用以下方法实现此功能:
char str1[] = "Hello, world!", *str2 = (char *)calloc (sizeof str1, sizeof (char));
strcpy (str2, str1);
由此可见:C++由于原生支持字符串类型,不需要通过字符数组存放字符串或通过字符指针指向字符串首地址,所以strcpy这类字符串函数在C++中也就没有用武之地了。C++就可以弃用strcpy这个函数了。
如果微软只在C++的编译过程中适用这种“弃用”规则,还不会引起很大的问题。然而微软在C语言的编译过程中也强行把C++中的这种“弃用”规则照搬过来,导致了一批C语言中的标准库函数虽有定义却无法使用,并且没有替代函数。在这种背景之下,微软造了一些只能用于MSVC的函数代替标准库函数。举个例子:标准库函数为scanf,微软自己的叫做scanf_s;微软强行规定scanf_s在输入字符/字符串时必须指定第三个参数。如标准库函数写作:
char c;
scanf ("%c", &c);
要改写成:
char c;
scanf_s ("%c", &c, 1);/* %c默认的输入宽度为1(等价于%1c),即使这样微软还是强行规定后面加上第三个参数 */
才能在MSVC上通过编译。
这些微软自己造的函数只能在Windows平台上使用,Linux等其他操作系统一概不支持。也就是说微软自己造的这些函数不能跨平台使用。
类似的问题还有:以下C语言程序是没有语法错误的
#include <stdio.h>
int main (void) {
int n;
scanf ("%d", &n);
int a[n];
for (int i = 0; i < n; i++) {
scanf ("%d", a + i);
}
for (int i = n - 1; i >= 0; i--) {
printf ((i < n - 1) ? "% d " : "% d\n", a[i]);
}
return 0;
}
然而在MSVC中,这段程序在编译时会产生臭名昭著的编译错误:C2057(应输入常量表达式)。这是因为C++不支持VLA,MSVC在编译C程序时会拒绝这种与C++标准不一致的C语言特性。
综上,编译C语言程序时不要使用MSVC,可以使用MinGW GCC或LLVM Clang等编译器。新版的VS可以在VS安装程序内安装Clang编译器。

