Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win


Porting C to C++

Posted on 2001-08-11
Medium Priority
Last Modified: 2010-04-02

I am in the process of moving a project from C to C++. We are talking about a project comprised of 10 C modules where only the main() function is in a C++ module.
This is a widely distrubted software running on many remote machines at nearly real-time environemt and performing very-high-priority tasks, thus I cannot make mistakes...
As the first step I renamed all the C modules to CPP and removed all the extern "C" from the code. The first thing that comes up is type-casting errors where C++ is more restrictive. Should I use the dynamic_cast and reinterpret_cast or rather the usual (type) cast?
Also any more vital advises you've got? (especially regarding how to prevent even the slightest decent in performance and stability)

Please respond ONLY if you had true experience with such an issue.

More info:
The reason I move from C to C++ is the compulsory need to use a C++ third-party code. I am not planning on changing the structure of my existing code.
The application relies stongly and deeply on alignment of the data structure. Should I be worried of alignment that is going to change in my sturcts?

Question by:mathought
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
  • 2
  • +1
LVL 32

Expert Comment

ID: 6376159
>>The application relies stongly and deeply on alignment of the data structure. Should I be worried of
alignment that is going to change in my sturcts?

My biggest concern here would NOT be from C -> C++ but rather from one vendor's compiler to another's.  (As least I think that's what you are saying.)

Expert Comment

ID: 6376192
The alignment issue can be solved with a compiler option
 (like /Zp1 in MS compilers).

I once had the task of converting legacy C code (I inherited (pun intended)) to be included with new C++ code.

The best advice I have is to only modify what's necessary.
I used the old-style casts where necessary.  There were not many.  I also re-evaluated the use of certain data types that required me to cast.  In the process, I cleared up some potential bugs.

Then I got curious and started wrappering the old functions into classes.  I learned a lot about the original design, but rewrote at least 25% of the code.

Later, that code had to be re-compiled for WinNT.  Luckily, I had made classes out of the old code.  It made the conversion (practically a rewrite) easier.  The conversion was pretty much a determination of what I could actually use.  Having 'like' grouped functionality in classes was a tremendous help.

Part of your decision has to do with your timeline, your familiarity with the original design and any future application for the code (or entire program).

If you're a true geek, you can compile and run the minimally changed code at work and do heavy experimentation at home.  Nothing to lose but time.

Accepted Solution

peterchen092700 earned 400 total points
ID: 6376379
a) do you need to call the C++ code from inside the C code?if not, you can wrap everything that "remains C" in
extern "C" { /* C code here */ }

* Alignment: /Zp1 (align by one byte) can be a bad idea if the original compile used word or DWORD alignment *and* the code relies on this. I would run the "old C" code and trace the structure sizes. then place asserts in you cpp code like 'assert(sizeof("NastyStruct") == 47)'. oh, and make sure that the byte size of char is the same on both compilers.

* Bit packed structures: Bits can be your downfall. if the code uses sth like
struct Bitpacked {  
  int x : 4;
  int y : 3;

there are several issues: a) the size of the entire thingie (esp. when size is less than sizeof(int)), and b) the location of the individual bits. You typically can control a) by a compiler option, but with b) you can't do much except rewriting your code. Most compilers do pack such structures tight, but they are allowed to add pd bits - e.g. to move y to the beginning of the next full byte)

* Warning Level:
A good idea is to the maximum warning level (typically 4), and examine all warnings seriously. This may be tons if you come rom C, so just clean up all warnings at Level 3.

* ANSI compatibility
If the original code is ANSI compatible, check the cpp compiler for an option like "ANSI compatibility mode", or "disable Non-standard extensions".

* Type casts: you should get along with static_cast, and reinterpret_cast where necessary. dynamic_cast is a C++ class specific cast. However, you should understand all casts and the difference beetween them. In short:

static_cast : implicit casts that sometimes come with a warning (like loosing precision):

int i;
char c = (char) i;
char c = static_cast<char>(i);

reinterpret_cast: "hard" cast - "interpret these bits as if they were of type <foo>"

void * p;
long l = *(l *)p
long l = *(reinterpret_cast<long *>(p))

(BTW, I have the habit to use C-style casts throughout my c++ projects, but it' a good idea to check each cast when coming from C, since existing C code tends to rely on compiler  & platform dependent facts)

It's been a long time since I did C --> C++, but I'm looking forward to ASM ==> C++ next year ;)

Good luck, and happy testing

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.


Expert Comment

ID: 6376391
I agree with peterchen's assessment on the /Zp1 thing.
It sounded as if I was suggesting to 1-byte align the code, but I should have said to match the byte alignment with the /Zp(n) option (if you use a compatible compiler).

Author Comment

ID: 6376901
I appreciate the advices, there is also one more issue. is it safe to replace all malloc() to new? Should I expect different behaviour once I move to new instead of malloc?

Expert Comment

ID: 6376955
depends on what you call (or rather: your existing source) "different".

Practically, I would make this decision dependent on how much you expect the project to change *after* being revamped to C++. If you don't expect the project to grow very much, I'd strongly suggest stay with malloc/free, as the change is error prone and the only benefit you don't have the hassle of mixing delete and free later.

Technicaly, the following differences exist or can exist:

new/delete calls constructors & destructors on it's elements. Since they are most likely intrinsic vars structs that don't have such, there sould be no *real* difference

new is "type-aware". Although it's common to replace malloc(n) with ((void *)(new char[n]), and free(p) with delete ((char*)p), this has no "positive side effect" and it might be dead wrong on some compilers and platforms, for memory alignment and byte size of "char". It works on an x86 platform, though.

the actual memory allocated by new may differ (storing array lenght, using different allocation scheme,...) VC++' new calls malloc internally.

most compilers offer a non-standard "get allocation size" function for malloc, but not for new.

All these differences are negligible if the C code is well written - but the C I encountered (or wrote) often tends to rely on implementation specifics, so your milage may vary. Anyway, if your code ist that crude, it might not even survive the new compiler.


Author Comment

ID: 6381112
Thanks for the descriptive commnts, everyone.

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

610 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question