强取豪夺by南枝txt下载:C和C++有什么不同之处?

来源:百度文库 编辑:中科新闻网 时间:2024/05/10 11:46:47
说详细点.

--------------------------------------------------------------------------------

将标准 C++ 视为一个新语言
Learning Standard C++ as a New Language
作者 Bjarne Stroustrup
译者 陈崴
就别再把 C++ 视为 C 的后一个语言了吧。这个问题问 C++ 之父就对了。

侯捷注:本文系北京《程序员》杂志 2001/04 的文章。译笔顺畅,技术饱满。
承译者陈崴先生与《程序员》杂志负责人蒋涛先生答允,
转载於此,以飨台湾读者,非常感谢。

未得陈崴先生与蒋涛先生二人之同意,任何人请勿将此文再做转载。

--------------------------------------------------------------------------------

C/C++ User's Journal May,1999

Learning Standard C++ as a New Language

by Bjarne Stroustrup

--------------------------------------------------------------------------------

导入
想要获得标准 C++ [叁考资料 1] 的最大优点,我们必须重新思考 C++ 程式的撰写方式。重新思考的方式之一就是,想想 C++ 应该如何学习(和教育)。我们应该强调什麽样的编程技术?我们应该先学习这个语言的哪一部份?在真正程式码中我们想要突显的又是哪一部份?

这篇文章把几个简单的 C++ 程式拿来比较,其中有些以现代化风格(使用标准程式库)撰写,有些以传统的 C 语言风格撰写。从这些简单例子所学到的功课,对大程式而言仍然具有重要意义。大体而言,这篇文章主张将 C++ 视为一个更高阶的语言来使用,这个语言依赖抽象性提供简练与优雅,但又不失低阶风格下的效率。

我们都希望程式容易撰写,正确执行,易於维护,并且效率可被接受。这意味我们应该以最接近此一理想的方式来使用 C++(或任何其他语言)。我猜想 C++ 族群尚未能够消化标准 C++ 所带来的种种设施;重新思考我们对 C++ 的使用方式,可获得一些重要的改善并进而达到上述理想。本文所重视的编程风格,焦点在於充份运用标准 C++ 所支援的设施,而不在那些设施本身。

主要的改善关键就是,透过对程式库的运用,降低我们所写的码的大小和复杂度。以下我要在一些简单例子中,示范并量化这些降低程度。这类简单实例可能出现在任何 C++ 导入性课程中。

由於降低了大小和复杂度,我们也就减少了开发时间,减轻了维护成本,并且降低了测试成本。另一个重点是,透过程式库的运用,我们还可以简化 C++ 的学习。对於小型程式以及只求获得好成绩的学生而言,这样的简化应该是相当充裕的了。然而专业程式员对效率极为要求,只有在效率不被牺牲的情况下,我们才能期许自己提升编程风格,以满足现代化服务和商务之於资料和即时回应的严格需求。为此我展示了一份量测结果,证明复杂度的降低并不会损失效率。最后我还讨论了这种观点对於学习和教育 C++ 所带来的影响。

复杂度 Complexity
试考虑一个题目,它很适合做为程式语言课程的第二道练习(译注:第一道练习当然是 "hello world" 啦):

输出一个提示句 “Please enter your name”
读入名字
输出“Hello <name>”

在标准 C++ 中,明显的解答是:

#include<iostream> // 取得标准 I/O 设施
#include<string> // 取得标准 string 设施

int main()
{
// 获得对标准程式库的取用权利
using namespace std;

cout << "Please enter your name: \n";
string name;
cin >> name;
cout << "Hello" << name << '\n';
}

对一个真正的初学者,我们必须解释整个架构。什麽是 main()?#include 做了些什麽事?using 做什麽用?此外我们还得对所有的细琐规榘有所了解,例如 \n 的意义,哪里应该加上分号┅等等。

然而这个程式的主要成份,观念非常简单,和题目的文字叙述之间只是表示法的不同。我们必须学习这种表示法,那很简单:string 就是一个 string(字串),cout 就是一个 output(输出设备),<< 就是一个我们用来写到输出设备去的运算子┅等等等。

为了进行比较,下面是传统的 C-style 解法 [注 1]:

#include<stdio. h> // 取得标准的 I/O 设施

int main()
{
const int max = 20; // name 的最大长度为 19
char name[max];

printf("Please enter your name: \n");

// 将字元读入 name 之中
scanf( "%s" , name);
printf( "Hello %s\n" ,name);

return 0;
}

很明显,主要逻辑有了轻微的 — 只是轻微的 — 改变,比 C++-style 版本复杂一些,因为我们必须解释阵列和怪异符号 %s。主要的问题在於,这个简单的 C-style 解答没什麽价值。如果有人输入一个长度大於 19 的名字(所谓 19,是上述指定的 20 再减 1 ,扣除的那个 1 用来放置 C-style 字串的结束字元),这个程式就完蛋了。

有人认为这种劣质品其实不会造成伤害,只要运用「稍后介绍」的某种适当解法。然而就算如此,引起争议的那一行也只不过是「可接受」而已,还达不到「良好」的境界。理想上我们不应该让一个菜鸟使用者面对一个容易当机的程式。

这个 C-style 程式如何才能够像 C++-style 程式一样地举止合宜呢?首先我们可以适度运用 scanf 来避免阵列溢位(array overflow):

#include<stdio. h> // 取得标准的 I/O 设施

int min()
{
const int max 20;
char name [max];

printf( "Please enter your first name: \n");
scanf( "%19s", name); // 读入最多 19 个字元
printf( "Hello %s\n", name);

return 0;
}

没有什麽标准方法可以直接在 scanf 的格式字串中直接使用符号型式的缓冲区大小,所以我必须像上面那样地使用整数字面常数。那是一种不良风格,也是日后维护时的一颗不定时炸弹。下面是专家级的作法,但实在难以对初学者启口:

char fmt[10];
// 产生一个格式字串,如使用单纯的 %s 可能会造成溢位(overflow)
sprintf(fmt, "%%%ds", max-1);
// 读入至多 max-1 个字元到 name 之中。
scanf(fmt, name);

犹有进者,这个程式会把 "超过缓冲区大小" 的字元砍掉。然而我们却希望字串能随着输入而成长。为了做到这一点,我们必须将抽象性下降到一个较低层次,处理个别的字元:

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>

void quit()
{
// 写出错误讯息并离开
fprintf( stderr, "memory exhausted\n");
exit (1);
}

int main()
{
int max= 20;
// 配置缓冲区:
char* name = (char*) malloc(max);
if (name ==0) quit();
printf( "Please enter your first name: \n");

// 跳过前导的空白字元
while (true) {
int c = getchar();
if (c = EOF) break; // 档案结束
if (!isspace(c)) {
ungetc (c, stdin);
break;
}
}

int i = 0;
while (true) {
int c = getchar();
if (c == '\n' || c == EOF) {
// 在尾端加上结束字元 0
name[i] = 0;
break;
}
name[i] = c;
if (i == max-1) { // 缓冲区填满了
max = max+max;
name = (char*) realloc(name, max);
if (name == 0) quit();
}
itt;
}

printf( "Hello %s\n", name);
free(name); // 释放记忆体
return 0;
}

和先前的版本比较,这个版本明显复杂得多。加上一段「跳过前导空白字元」的处理,使我感觉有些罪恶,因为我并未在题目叙述中明白提出这项需求。不过「跳过前导空白字元」是很正常的行为,稍后其他版本也都会这麽做。

可能有人认为这个例子并不是那麽糟糕。大部份有经验的 C 程式员和 C++ 程式员在真正的应用程式中或许(顺利的话)已经写过某些这样的东西。我们甚至可能认为,如果你写不出那样的程式,你就不能算是一个专业程式员。然而,想想这些东西加诸於初学者的观念负担吧。上面这个程式使用七个不同的 C 标准函式,在非常琐屑的层次上处理字元层面的输入,运用了指标,并自行处理自由空间(free store,译注:通常即是 heap)。为了使用 realloc,我必须采用 malloc(而不是 new)。这把我们带入了大小和型别转换 [注 2] 的议题。在一个如此的小程式中,什麽才是处理可能发生之记忆体耗尽问题的最佳作法呢?答案并不明显。这里我只是做某些事情,以杜绝这个讨论变质为另一个毫不相干的主题。惯用 C-style 作法的人必须谨慎地想想,哪一种作法对於更深一层的教学和最后的实际运用能够形成良好的基础。

总结来说,为了解决原本那个简单问题,除了问题核心本身,我还得介绍回圈,测试,储存空间之大小,指标,转型,以及自由空间之显式管理。而且这种编程风格充满了出错的机会。感谢长久累积下来的经验,我才能够避免出现任何明显的大小差一错误( off-by-one)或记忆体配置错误。我在面对 stream I/O 时,一开始也犯了典型的初学者错误:读入一个 char(而不是一个 int)并忘记检查 EOF。在 C++ 标准程式库尚未出现的那个年代,一点也不令人惊讶,许多教师无法摆脱这些不值钱的东西,暂时搁置它们稍后再教。不幸的是,许多学生也仅仅注意到这种劣等风格 "够好",写起来比其 C++ style 兄弟快。於是他们养成了一种很难打破的习惯并留下一条容易犯错的轨迹。

最后那个 C-style 程式有 41 行,而功能相当的 C++-style 程式只有 10 行。扣除基本架构之后,比值是 30 : 4。更重要的是, C++-style 的那几行不但较短,其本质也比较容易被了解。C++-style 和 C-style 两种版本的行数及观念复杂度很难客观量测,但我认为 C++-style 版本有 10 : 1 的优势。

效率 Efficiency
对一个无关痛痒如上述小例子的程式而言,效率算不上是个议题。面对这类程式,简化和(型别)安全才是重点所在。然而,真正的系统往往由一些极重视效率的成份组成。对於这类系统,问题就变成了 "我们能够给予较高阶的抽象性吗?"

考虑这类重视效率的程式,下面是个简单的例子:

读入未知数量的元素
对每个元素做某些动作
做某些涉及所有元素的动作

我能够想到的最简单而明确的例子就是,在程式中计算来自输入装置的一系列双精度浮点数的平均值(mean)和中间值( median)。下面是传统的 C-style 解法:

// C-style 解法:
#include<stdlib.h>
#include<stdio.h>

// 一个比较函式,稍后将给 qsort() 使用。
int compare (const void* p, const void* q)
{
register double p0 = * (double* )p;
register double q0 = * (double*)q;
if (p0 > q0) return 1;
if (pO < qO) return -1;
return 0;
}

void quit()
{
fprintf(stderr, "memory exhausted\n");
exit(1);
}

int main(int argc, char*argv[])
{
int res = 1000; // 最初的配置量
char* file = argv[2];
double* buf= (double*) malloc(sizeof(double) * res);
if (buf == 0) quit();

double median = 0;
double mean = 0;
int n = 0;

FILE* fin = fopen(file, "r"); // 开档做为输入用(reading)
double d;
while (fscanf(fin, "%lg", &d) == 1) {
if(n == res) {
res += res;
buf = (double*) realloc(buf, sizeof(double) * res);
if (buf == 0) quit();
}
buf[n++] = d;
// 有 rounding errors 的倾向
mean = (n==1) ? d : mean+(d-mean)/n;
}

qsort(buf, n, sizeof(double), compare);

if (n) {
int mid=n/2;
median = (n%2) ? buf[mid] : (buf[mid-1]+buf[mid])/2;
}

printf( "number of elements=%d, median=%g, mean=%g\n",
n, median, mean);

free(buf);
}

下面是常见的 C++ 解法:

// 使用 C++ 标准程式库的解法:

#include <vector>
#include <fstream>
#include <algorithm>

using namespace std;

main(int argc, char*argv[])
{
char* file = argv[2];
vector<double> buf;

double median = 0;
double mean = 0;

fstream fin(file,ios::in);
double d;
while (fin >> d) {
buf.push_back(d);
mean = (buf.size() == 1) ?
d : mean+(d-mean)/buf.size();
}
sort(buf.begin(),buf.end());

if (buf.size()) {
int mid = buf.size() /2;
median =
(buf.size() % 2) ?
buf[mid] : (buf[mid-1] + buf[mid] )/2;
}

cout << "number of elements = " << buf.size()
<< ", median = " << median << ", mean = "
<< mean << '\n';
}

这两个程式的大小,不再像前一个例子有那麽悬殊的差异(43 : 24,空行不计)。扣除无法删减的共同元素,例如 main() 的宣告和中间值的计算(共 13 行),两者的行数差异是 20 : 11。关键性的「输入并储存」回圈和排序动作,在 C++-style 程式中都有显着的缩短(「输入并储存」回圈的行数差异是 9 : 4,排序动作的行数差异是 9 : 1)。更重要的是,在 C++ 版本中,每一行所包含的逻辑远远简单得多 — 获得正确性的机会当然也就多得多。

再一次,记忆体管理在 C++-style 程式中隐喻实施;当元素以 push_back 加入,vector 便自动成长。C-style 程式则是以 realloc 做记忆体显式管理。出现在 C++-style 程式中的 vector 建构式和 push_back 函式会做掉 C-style 程式中的 malloc, realloc 动作,以及对於「被配置之记忆体大小」的追踪动作。在 C++-style 程式中,我依赖异常处理(exception handling)来记录记忆体的耗尽。在 C-style 程式中,我明白地测试以避免可能的记忆体耗尽问题。

一点也不令人惊讶,C++ 版本比较容易获得正确。我以剪贴的方式从 C-style 版本产生出这个 C++-style 版本。我忘记含入<algorithm>;我留下了 n 而忘了使用 buf.size;此外,我的编译器不支援局域( local)内的 using 指令,迫使我必须把它移到 main 之外。修正了这四个错误之后,程式就可以正确执行了。

对一个初学者而言,qsort 很是诡异。为什麽你必须给予元素个数?(因为阵列不知道它自己有多少个元素)为什麽你必须给予 double 的大小?(因为 qsort 不知道它要排序的单位是 doubles.)为什麽你必须写那个丑陋的、用来比较 doubles 数值的函式?(因为 qsort 需要一个指标指向某个函式,因为它不知道它所要排序的元素型别)为什麽 qsort 所使用的比较函式接受的是 const void* 引数而不是 char* 引数?(因为 qsort 可以对非字串的数值排序)void* 是什麽意思?前面加上 const 又是什麽意思?(唔,稍后我们再来谈这个话题)对初学者解释这些问题,恐怕很难不使他们两眼发直。相较之下解释 sort(v.begin( ), v.end()) 就容易得多:「单纯的 sort(v) 比较简单,但有时候我们想要对容器的某一部份做排序,所以更一般化的方式就是指定排序运作范围」。

为了比较效率,我首先必须决定多少笔输入才能使效率的比较饶富意义。由於 50,000 笔资料也不过是用了此程式半秒钟不到, 因此我选择以 500,000 笔输入和 5,000,000 笔输入来做比较。结果显示於表一。

表一 / 读入、排序、输出 浮点数

最佳化前 最佳化后
C++ C C/C++ 比值 C++ C C/C++ 比值
500,000 笔资料 3.5 6.1 1.74 2.5 5.1 2.04
5,000,000 笔资料 38.4 172.6 4.49 27.4 126.6 4.62

关键数字在於比值。比值大於 1 表示 C++-style 版本比较快。语言、程式库、编程风格之间的比较,众所周知十分棘手,所以请不要根据这些简单的测试就做出彻底的结论。这些比值是不同机器上数次执行结果的平均值。同一个程式的不同执行环境,其间差异低於 1 个百分比。我也执行了我这个 C-style 程式的 ISO C 严格相容版本,一如预期,其间并没有效率上的差异。

我预期 C++-style 程式会稍微快一点点。检验不同的 C++ 编译器实作品后,我发现执行结果有着令人惊讶的变化。某些时候, C-style 版本在小资料量的情况下表现优於 C++- style 版本。然而本例的重点在於,我们可以面对目前已知的技术,提供一个较高阶的抽象性和一个针对错误的较佳保护。我所使用的 C++ 编译器既普遍又便宜 — 不是研究室里的玩具。那些宣称可以提供更高效率的编译器,当然也适用本结果。

要找到一些人,愿意在方便性和较佳的错误防范上面付出 3, 10 或甚至 50 的比值,倒也还不罕见。但如果把这些效益放在一起,再加上两倍或四倍的速度,那就非常壮观而吸引人了。这些数字应该是一个 C++ 程式库供应商乐意接受的最小值。为了知道时间花在什麽地方,我又进行了一些额外测试(见表二)。

表二 / 读入浮点数并排序。为了解输入动作所耗费的成本,我加上一个 "generate" 函式,用来产生随机数值。

500,000 笔资料:

最佳化前 最佳化后
C++ C C/C++ 比值 C++ C C/C++ 比值
读入资料 read 2.1 2.8 1.33 2.0 2.8 1.4
产生资料 generate 0.6 0.3 0.5 0.4 0.3 0.75
读入并排序 read & sort 3.5 6.1 1.75 2.5 5.1 2.04
产生并排序 generate & sort 2.0 3.5 1.75 0.9 2.6 2.89

5,000,000 笔资料:

最佳化前 最佳化后
C++ C C/C++ 比值 C++ C C/C++ 比值
读入资料 read 21.5 29.1 1.35 21.3 28.6 1.34
产生资料 generate 7.2 4.1 0.57 5.2 3.6 0.69
读入并排序 read & sort 38.4 172.6 4.49 27.4 126.6 4.62
产生并排序 generate & sort 24.4 147.1 6.03 11.3 100.6 8.9

当然,"read" 仅仅只是读入资料,"read&sort" 仅仅只是读入资料并排序,它们都不会产生任何输出。为了对输入成本获得比较好的感觉,"generate" 用来产生随机数值,而非从输入设备读入资料。

在其他的例子和其他的编译器身上,我料想 C++ stream I/O 会比 stdio 稍稍慢一些。本程式的前一版本使用 cin 而非 file stream,情况的确如此。在某些 C++ 编译器上,档案的 I/O 确实远比 cin 快速得多,其理由至少有一部份是因为 cin 和 cout 之间的系结的拙劣处理。然而,以上数值显示,C++-style I/O 可以像 C-style I/O 一样地有效率。

如果改变这些程式,使它们读入并排序的对象是整数而非浮点数,并不会改变相对效率 — 虽然我们可以惊喜地发现,这种改变对 C++-style 程式而言实在非常简单(只需两个改变,C-style 程式需要 12 个改变)。这对於易维护性是一个好兆头。 "generate" 测试所呈现的差异显示出配置所花费的成本。一个 vector 加上 push_back 应该就像一个阵列加上 malloc/free 一样快,但实际却非如此。其原因是难以在最佳化过程中将「什麽事都没做的初值设定列( initializers)」的呼叫动作去除。幸运的是,配置所引发的成本,在输入(造成配置需求)所引发的成本面前,几乎总是显得渺小。至於 sort,一如预期远比 qsort 快得多,主要原因是 sort 内的比较动作是行内展开(inlines),而 qsort 必须呼叫某个函式。

实在很难选择一个例子可以好好说明效率议题。我从同事身上获得的意见是,读入并比较「数值」还不够写实,应该读入「字串」并排序。所以我写了以下程式:

#include<vector>
#include<fstream>
#include<algorithm>
#include<string>

using namespace std;

int main(int argc, char* argv[])
{
char* file = argv[2]; // 输入档的档名
char* ofile = argv[3]; // 输出档的档名

vector<string> buf;

fstream fin (file,ios::in);
string d;
while (getline (fin, d))
buf.push_back (d);

sort(buf.begin(), buf.end());

fstream fout (ofile, ios: out);
copy(buf.begin(), buf.end(),
ostream_iterator<string> (fout, "\n"));
}

我把它改写为 C 的型式,并设法让字元的读入得以最佳化。C++-style 版本执行得很好 — 即使是面对经过手动调整而达到最佳化效果的 C-style 版本(后者消除了字串的拷贝动作)。对於小量输出而言,没有什麽显着差异,但对於大量资料而言,sort 再一次击败了 qsort,因为其较佳的行内展开(inlines),见表三。

表三 / 读入、排序、输出 字串

C++ C C/C++
比值 C,去除
字串拷贝动作 最佳化后的
C/C++ 比值
500,000 笔资料 8.4 9.5 1.13 8.3 0.99
2,000,000 笔资料 37.4 81.3 2.17 76.1 2.03

我采用两百万笔字串,因为我没有足够的主记忆体来容纳五百万个字串而不引起分页置换(paging)。

为了知道时间花费在哪里,我也执行了刻意遗漏 sort 的程式(见表格四)。我所准备的字串相对较短(平均由七个字元构成)。

表四 / 读入并输出字串 — 刻意遗漏 sort

C++ C C/C++
比值 C,去除
字串拷贝动作 最佳化后的
C/C++ 比值
500,000 笔资料 2.5 3.0 1.2 2 0.8
2,000,000 笔资料 9.8 12.6 1.29 8.9 0.91

注意,string 是一个很完美的使用者自定型别,而它只不过是标准程式库的一部份而已。如果我们能够因为使用 string 而获得效率和精致,我们也能够因为使用其他使用者自定型别而获得效率和精致。

为什麽我要在编程风格和教学的文章中讨论效率呢?因为,编程风格以及我们所教导的技术,必须为真实世界的问题服务。 C++ 的创造是为了运用於大规模系统以及对效率有严格规范的系统。因此我认为,如果 C++ 的某种教育方式会导致人们所使用的编程风格和技术只在玩具程式中才有效率可言,那是令人无法 同的,那会使人们挫败并因而放弃学习。以上的量测结果显示,如果你的 C++ 风格极为依赖泛型编程(generic programming)和具象型别,以此提供更简单更达到「型别安全(type-safe)」的码,其效率可以和传统的 C 风格一较长短。类似的结果在物件导向(object-oriented)风格中也可获得。

不同的标准程式库实作品的效率表现,有戏剧性的差异,这是一个重要问题。对一个决定大量依赖标准程式库(或广为流传的非标准程式库)的程式员而言,很重要的一点是,你所采用的编程风格应该能够在不同的系统上都有至少可被接受的效率。我很惊骇地发现,我的测试程式在某个系统上,C++ style 和 C style 相比有两倍快,而在另一个系统上却只有一半快。如果系统间的变动因素超过 4,程式员就不该接受。就我所能理解,这种变异性并非由於基本因素而形成,所以不需要程式库实作者过份夸张的努力,就应该可以达到效率的一致性。采用优化程度较佳的程式库,或许是改善对标准 C++ 的认知和实际效率表现的最轻易方式。是的,编译器实作者很努力地消除各个编译器之间的微小效率差异;我估量在效率方面,标准程式库的实作者影响较大。

很明显,上述 C++-style 解法相较於 C-style 解法所带来的编程与逻辑上的简化,可以藉由 C++ 标准程式库而达到。这样的比较是否不够实在或不够公平呢?我不这麽认为。C++ 的一个关键形貌就是,它对程式库的支援能力,精致而且高效。上述简单程式所展现的种种优点,在任何应用领域中都可以保持 — 只要其间存在着精致而高效率的程式库。C++ 族群的挑战在於扩充领域,让一般程序员也都享受得到这些利益。也就是说,我们必须针对更多应用领域,设计并实作精致而富有效率的程式库,并让这些程式库被广泛运用。

学习 C++
即使是专业程序员,也不可能一开始就先将整个语言的全貌学习完毕,然后才开始使用它。程式语言应该要分段学习,以小型的练习来试验其种种设施。所以我们总是以分段精通的方式来学习一个语言。真正的问题不在於 "我应该先学习语言的一部份吗?" 而在於 "我应该先学习语言的哪一部份?"

关於这个问题,传统的回答是 "先学习 C++ 中与 C 相容的子集"。但是从我所思考的观点来看,这不是一个好答案。这种学习法会导致过早专注於低阶细节。它也会因为强迫学生过早面对许多技术难点而模糊了编程风格与设计上的议题,进而压抑了许多有趣的东西。本文先前的两个例子已经说明这一点。C++ 拥有较佳的程式库支援,较佳的表示法,较佳的型别检验,无疑地在在对於 "C 优先" 的作法投了一张反对票。然而,注意,我也并不是说要 "纯粹

面向过程和面向对象的区别 具体有好多细节都不一样

C没有两个+

C++是比C更高级的一种语言,他是在C上的继承和扩展,引入了类\继承\面向对象的概念;而C只是面向过程.

C++从C进化而来,C语言的超集.
C中的结构与C++中的结构之差异,C中的函数名与C++中的函数名之差异.

C++ 踩在 C 的肩膀上。C 踩在汇骗的肩膀上。没有汇骗就没有C,没有C也就没有C++, C#, Java,以及工具 VB, VC, PB, C++Builder 等(Delphi 那个怪物有点例外,类库用Pascal写成,不知内核中是否用到C)。最历害的是汇编啊,笨。

Win32 的所有 SDK 都是用 C或汇编 为 C 开发的。C++靠边站。Java 的本地方法也是针对 C的。各平台下网络编程API都是针对C的,C++不会让你们拿到满意的工资,C ++是C的超集,但实际上对你或公司来说,最挣钱是C的那部分。C 已流行了30 年,在当今,它还是与硬件离得最近的高级语言,离平台最近的高级语言,离网络最近的高级语言。虽然在大多情况下c++比C 简单,但C的门槛其实比C++高。

“C++在开发上比C省事多了,现在很少用C做开发了,只有特殊情况下才用到。”这种说法太片面了,纯粹在PC上做事情可能如此。

真正的高手可以离开汇编,但绝不愿意离开C,因为有很多事情C++不能胜任。真正的汇编高手写出的代码简直就是艺术品。因为语言越低级,需要考虑的事情就越多。C++跟C比起来,唯一的优势是它的先进的编程思想。优秀的C程序员能把C++的编程思想发挥的淋漓尽致!