从 C++ 迁移到 C
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4058496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Moving from C++ to C
提问by george
After a few years coding in C++, I was recently offered a job coding in C, in the embedded field.
在使用 C++ 编码几年后,我最近获得了一份嵌入式领域的 C 编码工作。
Putting aside the question of whether it's right or wrong to dismiss C++ in the embedded field, there are some features/idioms in C++ I would miss a lot. Just to name a few:
撇开在嵌入式领域忽略 C++ 是对还是错的问题不谈,C++ 中有一些特性/习语我会错过很多。仅举几个:
- Generic, type-safe data structures (using templates).
- RAII. Especially in functions with multiple return points, e.g. not having to remember to release the mutex on each return point.
- Destructors in general. I.e. you write a d'tor once for MyClass, then if a MyClass instance is a member of MyOtherClass, MyOtherClass doesn't have to explicitly deinitialize the MyClass instance - its d'tor is called automatically.
- Namespaces.
- 通用的、类型安全的数据结构(使用模板)。
- 铁路。特别是在具有多个返回点的函数中,例如不必记住在每个返回点上释放互斥锁。
- 一般的析构函数。即,您为 MyClass 编写了一次 d'tor,然后如果 MyClass 实例是 MyOtherClass 的成员,则 MyOtherClass 不必显式取消初始化 MyClass 实例 - 它的 d'tor 会自动调用。
- 命名空间。
What are your experiences moving from C++ to C?
What C substitutes did you find for your favorite C++ features/idioms? Did you discover any C features you wish C++ had?
您从 C++ 迁移到 C 有什么经验?
您为您最喜欢的 C++ 特性/习语找到了哪些 C 替代品?您是否发现了您希望 C++ 拥有的任何 C 特性?
采纳答案by Mike DeSimone
Working on an embedded project, I tried working in all C once, and just couldn't stand it. It was just so verbose that it made it hard to read anything. Also, I liked the optimized-for-embedded containers I had written, which had to turn into much less safe and harder to fix #define
blocks.
在处理嵌入式项目时,我曾尝试使用所有 C 语言,但实在受不了。它是如此冗长,以至于很难阅读任何内容。此外,我喜欢我编写的针对嵌入式优化的容器,它们必须变得不那么安全且更难修复#define
块。
Code that in C++ looked like:
C++ 中的代码如下所示:
if(uart[0]->Send(pktQueue.Top(), sizeof(Packet)))
pktQueue.Dequeue(1);
turns into:
变成:
if(UART_uchar_SendBlock(uart[0], Queue_Packet_Top(pktQueue), sizeof(Packet)))
Queue_Packet_Dequeue(pktQueue, 1);
which many people will probably say is fine but gets ridiculous if you have to do more than a couple "method" calls in a line. Two lines of C++ would turn into five of C (due to 80-char line length limits). Both would generate the same code, so it's not like the target processor cared!
许多人可能会说这很好,但如果您必须在一行中执行多个“方法”调用,则这会变得荒谬。两行 C++ 将变成五行 C(由于 80 个字符的行长度限制)。两者都会生成相同的代码,所以它不像目标处理器那样关心!
One time (back in 1995), I tried writing a lot of C for a multiprocessor data-processing program. The kind where each processor has its own memory and program. The vendor-supplied compiler was a C compiler (some kind of HighC derivative), their libraries were closed source so I couldn't use GCC to build, and their APIs were designed with the mindset that your programs would primarily be the initialize/process/terminate variety, so inter-processor communication was rudimentary at best.
有一次(早在 1995 年),我尝试为多处理器数据处理程序编写大量 C。每个处理器都有自己的内存和程序的那种。供应商提供的编译器是一个 C 编译器(某种 HighC 派生类),他们的库是闭源的,所以我不能使用 GCC 来构建,他们的 API 的设计理念是你的程序将主要是初始化/进程/terminate 多样性,因此处理器间通信充其量只是基本的。
I got about a month in before I gave up, found a copy of cfront, and hacked it into the makefiles so I could use C++. Cfront didn't even support templates, but the C++ code was much, much clearer.
在我放弃之前大约一个月,我找到了cfront的副本,并将其破解到生成文件中,以便我可以使用 C++。Cfront 甚至不支持模板,但 C++ 代码要清晰得多。
Generic, type-safe data structures (using templates).
通用的、类型安全的数据结构(使用模板)。
The closest thing C has to templates is to declare a header file with a lot of code that looks like:
C 与模板最接近的事情是声明一个包含大量代码的头文件,如下所示:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{ /* ... */ }
then pull it in with something like:
然后用类似的东西把它拉进去:
#define TYPE Packet
#include "Queue.h"
#undef TYPE
Note that this won't work for compound types (e.g. no queues of unsigned char
) unless you make a typedef
first.
请注意,unsigned char
除非您先创建,否则这不适用于复合类型(例如,没有 的队列)typedef
。
Oh, and remember, if this code isn't actually used anywhere, then you don't even know if it's syntactically correct.
哦,记住,如果这段代码实际上没有在任何地方使用,那么你甚至不知道它在语法上是否正确。
EDIT:One more thing: you'll need to manuallymanage instantiation of code. If your "template" code isn't allinline functions, then you'll have to put in some control to make sure that things get instantiated only once so your linker doesn't spit out a pile of "multiple instances of Foo" errors.
编辑:还有一件事:您需要手动管理代码的实例化。如果您的“模板”代码不是全部内联函数,那么您必须进行一些控制以确保事物仅被实例化一次,这样您的链接器就不会吐出一堆“Foo 的多个实例”错误.
To do this, you'll have to put the non-inlined stuff in an "implementation" section in your header file:
为此,您必须将非内联内容放在头文件的“实现”部分中:
#ifdef implementation_##TYPE
/* Non-inlines, "static members", global definitions, etc. go here. */
#endif
And then, in oneplace in all your code per template variant, you have to:
然后,在每个模板变体的所有代码中的一个地方,您必须:
#define TYPE Packet
#define implementation_Packet
#include "Queue.h"
#undef TYPE
Also, this implementation section needs to be outsidethe standard #ifndef
/#define
/#endif
litany, because you may include the template header file in another header file, but need to instantiate afterward in a .c
file.
此外,这实现部分需求是外标准#ifndef
/ #define
/#endif
一长串,因为你可能包括另一头文件模板头文件,但需要实例化后的.c
文件。
Yep, it gets ugly fast. Which is why most C programmers don't even try.
是的,它变得丑陋很快。这就是为什么大多数 C 程序员甚至不尝试的原因。
RAII.
铁路。
Especially in functions with multiple return points, e.g. not having to remember to release the mutex on each return point.
特别是在具有多个返回点的函数中,例如不必记住在每个返回点上释放互斥锁。
Well, forget your pretty code and get used to all your return points (except the end of the function) being goto
s:
好吧,忘记你漂亮的代码并习惯你所有的返回点(除了函数的结尾)都是goto
s:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{
TYPE * result;
Mutex_Lock(this->lock);
if(this->head == this->tail)
{
result = 0;
goto Queue_##TYPE##_Top_exit:;
}
/* Figure out `result` for real, then fall through to... */
Queue_##TYPE##_Top_exit:
Mutex_Lock(this->lock);
return result;
}
Destructors in general.
一般的析构函数。
I.e. you write a d'tor once for MyClass, then if a MyClass instance is a member of MyOtherClass, MyOtherClass doesn't have to explicitly deinitialize the MyClass instance - its d'tor is called automatically.
即,您为 MyClass 编写了一次 d'tor,然后如果 MyClass 实例是 MyOtherClass 的成员,则 MyOtherClass 不必显式取消初始化 MyClass 实例 - 它的 d'tor 会自动调用。
Object construction has to be explicitly handled the same way.
对象构造必须以相同的方式显式处理。
Namespaces.
命名空间。
That's actually a simple one to fix: just tack a prefix onto everysymbol. This is the primary cause of the source bloat that I talked about earlier (since classes are implicit namespaces). The C folks have been living this, well, forever, and probably won't see what the big deal is.
这实际上是一个简单的修复:只需在每个符号上添加一个前缀。这是我之前谈到的源代码膨胀的主要原因(因为类是隐式命名空间)。C 语言的人一直生活在这种情况下,好吧,永远,并且可能看不出有什么大不了的。
YMMV
青年会
回答by Jens Gustedt
I moved from C++ to C for a different reason (some sort of allergic reaction ;) and there are only a few thing that I miss and some things that I gained. If you stick to C99, if you may, there are constructs that let you program quite nicely and safely, in particular
由于不同的原因(某种过敏反应;),我从 C++ 迁移到 C,并且只有一些我想念的东西和一些我获得的东西。如果你坚持使用 C99,如果可以的话,有一些结构可以让你很好地和安全地编程,特别是
- designated initializers (eventually combined with macros) make initialization of simple classes as painless as constructors
- compound literals for temporary variables
for
-scope variable may help you to do scope bound resource management, in particular to ensure tounlock
of mutexes orfree
of arrays, even under preliminary function returns__VA_ARGS__
macros can be used to have default arguments to functions and to do code unrollinginline
functions and macros that combine well to replace (sort of) overloaded functions
- 指定的初始化器(最终与宏结合)使简单类的初始化像构造函数一样轻松
- 临时变量的复合字面量
for
-scope 变量可以帮助您进行范围绑定的资源管理,特别是确保unlock
互斥锁或free
数组,即使在初步函数返回的情况下__VA_ARGS__
宏可用于为函数提供默认参数并进行代码展开inline
结合良好以替换(某种)重载函数的函数和宏
回答by d.s.
The difference between C and C++ is the predictability of the code's behavior.
C 和 C++ 之间的区别在于代码行为的可预测性。
It is a easier to predict with great accuracy what your code will do in C, in C++ it might become a bit more difficult to come up with an exact prediction.
用 C 语言更准确地预测你的代码会做什么更容易,在 C++ 中,想出一个准确的预测可能会变得有点困难。
The predictability in C gives you better control of what your code is doing, but that also means you have to do more stuff.
C 中的可预测性使您可以更好地控制代码正在做什么,但这也意味着您必须做更多的事情。
In C++ you can write less code to get the same thing done, but (at leas for me) I have trouble occasionally knowing how the object code is laid out in memory and it's expected behavior.
在 C++ 中,您可以编写更少的代码来完成相同的事情,但是(至少对我而言)我有时无法了解目标代码在内存中的布局方式及其预期行为。
回答by MOnsDaR
Nothing like the STL exists for C.
There are libs available which provide similar functionality, but it isn't builtin anymore.
没有像 C 那样的 STL 存在。
有提供类似功能的库可用,但它不再是内置的。
Think that would be one of my biggest problems... Knowing with which tool I could solve the problem, but not having the tools available in the language I have to use.
认为这将是我最大的问题之一......知道我可以使用哪种工具解决问题,但没有我必须使用的语言中的可用工具。
回答by Dan
In my line of work - which is embedded, by the way - I am constantly switching back & forth between C and C++.
在我的工作中——顺便说一下,这是嵌入的——我经常在 C 和 C++ 之间来回切换。
When I'm in C, I miss from C++:
当我使用 C 语言时,我会想念 C++:
templates (including but not limited to STL containers). I use them for things like special counters, buffer pools, etc. (built up my own library of class templates & function templates that I use in different embedded projects)
very powerful standard library
destructors, which of course make RAII possible (mutexes, interrupt disable, tracing, etc.)
access specifiers, to better enforce who can use (not see) what
模板(包括但不限于 STL 容器)。我将它们用于特殊计数器、缓冲池等(建立我自己的类模板和函数模板库,用于不同的嵌入式项目)
非常强大的标准库
析构函数,这当然使 RAII 成为可能(互斥体、中断禁用、跟踪等)
访问说明符,以更好地强制执行谁可以使用(看不到)什么
I use inheritance on larger projects, and C++'s built-in support for it is much cleaner & nicer than the C "hack" of embedding the base class as the first member (not to mention automatic invocation of constructors, init. lists, etc.) but the items listed above are the ones I miss the most.
我在较大的项目中使用继承,并且 C++ 对它的内置支持比将基类嵌入为第一个成员的 C“hack”(更不用说构造函数、初始化列表等的自动调用)更清晰和更好。 ) 但上面列出的项目是我最想念的项目。
Also, probably only about a third of the embedded C++ projects I work on use exceptions, so I've become accustomed to living without them, so I don't miss them too much when I move back to C.
此外,可能只有大约三分之一的嵌入式 C++ 项目使用异常,所以我已经习惯了没有它们的生活,所以当我回到 C 时我不会太想念它们。
On the flip side, when I move back to a C project with a significant number of developers, there are whole classes of C++ problems that I'm used to explaining to people which go away. Mostly problems due to the complexity of C++, and people who think they know what's going on, but they're really at the "C with classes" part of the C++ confidence curve.
另一方面,当我回到一个有大量开发人员的 C 项目时,我习惯于向人们解释一整类 C++ 问题。主要问题是由于 C++ 的复杂性,以及认为自己知道发生了什么的人,但他们确实处于C++ 置信曲线的“C 与类”部分。
Given the choice, I'd prefer using C++ on a project, but only if the team is pretty solid on the language. Also of course assuming it's not an 8K μC project where I'm effectively writing "C" anyway.
如果可以选择,我更喜欢在项目中使用 C++,但前提是团队在语言上非常扎实。当然也假设它不是一个 8K μC 项目,无论如何我都在有效地编写“C”。
回答by hhafez
Couple of observations
几个观察
- Unless you plan to use your c++ compiler to build your C (which is possible if you stick to a well define subset of C++) you will soon discover things that your compiler allows in C that would be a compile error in C++.
- No more cryptic template errors (yay!)
- No (language supported) object oriented programming
- 除非你打算使用你的 c++ 编译器来构建你的 C(如果你坚持一个定义良好的 C++ 子集,这是可能的)你很快就会发现你的编译器在 C 中允许的东西在 C++ 中会是编译错误。
- 不再有神秘的模板错误(是的!)
- 无(支持语言)面向对象编程
回答by Antihero
Pretty much the same reasons I have for using C++ or a mix of C/C++ rather than pure C. I can live without namespaces but I use them all the time if the code standard allows it. The reasons is that you can write much more compact code in C++. This is very usefull for me, I write servers in C++ which tend to crash now and then. At that point it helps a lot if the code you are looking at is short and consist. For example consider the following code:
与我使用 C++ 或 C/C++ 的混合而不是纯 C 的原因几乎相同。我可以没有命名空间,但如果代码标准允许,我会一直使用它们。原因是您可以用 C++ 编写更紧凑的代码。这对我来说非常有用,我用 C++ 编写服务器,它时不时会崩溃。在这一点上,如果您正在查看的代码简短且内容丰富,那将大有帮助。例如,考虑以下代码:
uint32_t
ScoreList::FindHighScore(
uint32_t p_PlayerId)
{
MutexLock lock(m_Lock);
uint32_t highScore = 0;
for(int i = 0; i < m_Players.Size(); i++)
{
Player& player = m_Players[i];
if(player.m_Score > highScore)
highScore = player.m_Score;
}
return highScore;
}
In C that looks like:
在 C 中看起来像:
uint32_t
ScoreList_getHighScore(
ScoreList* p_ScoreList)
{
uint32_t highScore = 0;
Mutex_Lock(p_ScoreList->m_Lock);
for(int i = 0; i < Array_GetSize(p_ScoreList->m_Players); i++)
{
Player* player = p_ScoreList->m_Players[i];
if(player->m_Score > highScore)
highScore = player->m_Score;
}
Mutex_UnLock(p_ScoreList->m_Lock);
return highScore;
}
Not a world of difference. One more line of code, but that tends to add up. Nomally you try your best to keep it clean and lean but sometimes you have to do something more complex. And in those situations you value your line count. One more line is one more thing to look at when you try to figure out why your broadcast network suddenly stops delivering messages.
不是天壤之别。多一行代码,但这往往会加起来。通常情况下,您会尽力保持清洁和精简,但有时您必须做一些更复杂的事情。在这些情况下,您会重视您的行数。当您试图弄清楚为什么您的广播网络突然停止传递消息时,多一行是另外一件事。
Anyway I find that C++ allows me to do more complex things in a safe fashion.
无论如何,我发现 C++ 允许我以安全的方式做更复杂的事情。
回答by KOkon
I think the main problem why c++ is harder to be accepted in embedded environment is because of the lack of engineers that understand how to use c++ properly.
我认为为什么c++在嵌入式环境中更难被接受的主要问题是因为缺乏了解如何正确使用c++的工程师。
Yes, the same reasoning can be applied to C as well, but luckily there aren't that many pitfalls in C that can shoot yourself in the foot. C++ on the other hand, you need to know when not to use certain features in c++.
是的,同样的推理也适用于 C,但幸运的是,C 中并没有那么多可以让自己陷入困境的陷阱。另一方面,C++,您需要知道何时不使用 C++ 中的某些功能。
All in all, I like c++. I use that on the O/S services layer, driver, management code, etc. But if your team doesn't have enough experience with it, it's gonna be a tough challenge.
总而言之,我喜欢c++。我在 O/S 服务层、驱动程序、管理代码等方面使用它。但是如果你的团队没有足够的经验,这将是一个艰巨的挑战。
I had experience with both. When the rest of the team wasn't ready for it, it was a total disaster. On the other hand, it was good experience.
我对两者都有经验。当团队的其他成员还没有准备好时,这完全是一场灾难。另一方面,这是很好的体验。
回答by kaynat liaqat
yes! i have experienced both of these languages and what i found is C++ is more friendly language. It facilitates with more features. It is better to say that C++ is superset of C language as it provide additional features like polymorphism, interitance, operator and function overloading, user defined data types which is not really supported in C. The thousand lines of code is reduce to few lines with the help of object oriented programming that's the main reason of moving from C to C++.
是的!我体验过这两种语言,我发现 C++ 是更友好的语言。它有助于提供更多功能。最好说 C++ 是 C 语言的超集,因为它提供了额外的特性,如多态性、互操作性、运算符和函数重载、用户定义的数据类型,这些在 C 中并不真正支持。千行代码减少到几行面向对象编程的帮助是从 C 迁移到 C++ 的主要原因。