|
-
May 3rd, 2011, 05:02 AM
#1
[RESOLVED] Differences in Code Generation Between C and C++ Compilers
I have an old program that is a Windows API program written in C. When I inherited the project, even though all the code was C, some of the files were cpp files. I know the C++ compiler catches more than the C compiler.
I had to add in some third party code that was a C++ class and made some other changes that were causing the linker to have problems with the types across the C and C++ modules, so I renamed all the modules to .CPP. It links and runs, but the code doesn't work right.
The program is a hardware test program that is supposed to put some hardware through its paces and generation a calibration file that is used by other programs. On the version compiled before I made the change to CPP, the tests run without errors on the hardware. With the all CPP file version, I'm getting a set of errors in one part of the program.
I have experimented commenting out all my changes and the same problems crop up.
I tried changing the optimization and I got different errors, but they were from the same part of the program. At this point, I'm beginning to think that there is something different about the code created with the C++ compiler that is causing the problems.
I am sure there is something structurally wrong with the code that was masked by compiling in C. I also believe there are some differences in calling conventions between C and C++, but I'm not sure what they are.
So my question is what are the differences in code between C compiled under C and under the C++ compilers? I'm using VC 2005 Pro BTW.
Thanks,
Bill
-
May 3rd, 2011, 07:22 AM
#2
Re: Differences in Code Generation Between C and C++ Compilers
 Originally Posted by wdolson
So my question is what are the differences in code between C compiled under C and under the C++ compilers? I'm using VC 2005 Pro BTW.
Thanks,
Bill
Just because a program "works" when compiled under another compiler doesn't mean the code was OK.
Bugs in C and C++ programs do not have to be exposed to you at runtime. There are many programs that have run for years that have hidden bugs, only to be exposed when the program has changes made to it, or the program is compiled using a different compiler, or when the program is run on that "special" computer (many times, the customer's computer).
When you compiled using the C++ compiler, did you have to make changes to the code for the compiler to accept the code as valid? If you did, what changes did you make? Did you make the sometimes fatal mistake of casting from one type to another to "fix" a C++ compiler error?
I don't think you should waste a lot of time trying to figure out if something is up with the compiler. If it is a hidden bug that always existed, then it wasn't worth trying to figure out if there is a difference in the C and C++ code, and just accept the fact that your program has bugs and address that issue.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; May 3rd, 2011 at 07:28 AM.
-
May 3rd, 2011, 07:48 AM
#3
Re: Differences in Code Generation Between C and C++ Compilers
Which is why I said in my first post "I am sure there is something structurally wrong with the code that was masked by compiling in C."
I didn't have to make any changes to the code itself to get it to compile with the C++ compiler. I did have to change some extern declarations to C++ style declarations.
In cleaning up the code, I also found many places where there was code like this:
if(key=foo(somevariable))
return key;
I changed this to:
key=foo(somevariable);
if(key)
return key;
I think it's cleaner code and it shuts up the compiler from squawking at me with warnings. Functionally it should make no difference though.
I also ran into some switch statements that didn't have a
break;
on the default case (last in the chain). It was working without it, but it's not very good practice.
Other than the cosmetic changes and the externs, I made no changes at all to the entire module that has the problem.
Bill
-
May 3rd, 2011, 08:08 AM
#4
Re: Differences in Code Generation Between C and C++ Compilers
Hi,
I suggest taking a close look at the changes to the externs.
If you're using this to debug hardware, maybe some port accesses are getting optimized out, or changed in some way that affects the interaction with the hardware. That would also tie in with you seeing a change in behaviour depending on the optimization level.
Alan
-
May 3rd, 2011, 08:47 AM
#5
Re: Differences in Code Generation Between C and C++ Compilers
What is "set of errors in one part of the program"? Compilation, linker errors? Program cannot start? Or it starts successfully and prints some error messages according to the program algorithm?
-
May 3rd, 2011, 03:22 PM
#6
Re: Differences in Code Generation Between C and C++ Compilers
Also, on programs that work closely with hardware, the way data is aligned and stored in memory can be critical. For example, the hardware might expect a sequence of data bits one after the other, with no padding in between. If you think this might be an issue, look into #pragma pack
-
May 4th, 2011, 11:09 PM
#7
Re: Differences in Code Generation Between C and C++ Compilers
Alan: I have a little bit older version pre-C++ conversion that I have been comparing against. I rebuilt the pre-C++ version with the same low level hardware access code as the new version is using. The pre-C++ version works with the hardware, the post C++ conversion version has the errors. The utility uses some of the same files as the real programs for hardware access. We've been using the hardware access code for a year with no problems. While it's possible there is something subtle in the hardware access code, I would say it's a lower probability than something unique to this utility.
I did experiment with different optimiztion in the compiler. Initially there was no optimization at all. With optimization, the code still ran, the test errors were even worse.
I went over the externs and everything looks in order, but it would probably be worth looking at them again.
Alex F: The hardware has a couple of analog to digital converters and the calibration program works a lot with the A/D converters. The errors happen when the A/D is converting a measurement of a voltage across a series resistor. The working version of the code is returning a positive voltage drop across the resistor, the errors in the C++ compiled version comes from the measurement across the resistor coming back equal to or less than the 0 volt measure done earlier. The 0 volt measure is the same between the two versions, so the problem is coming from the voltage drop across the resistor.
The program compiles and runs fine. The errors are false positives in tests on the hardware. The program is saying the hardware is failing. Other versions of the program do not flag any hardware problems. There are some known minor problems with the hardware I'm using (this hardware was rejects from production that were held back for development). It has been verified in the lab that the hardware does not have these problems and the errors reported are false positives.
MikeAThon: I tried changing the packing just to see what happened. I did get a new error on the hardware setting packing, but essentially no change.
-
May 5th, 2011, 01:12 AM
#8
Re: Differences in Code Generation Between C and C++ Compilers
Could it be a problem with signed/unsigned integers (or shorts or chars)?
Victor Nijegorodov
-
May 5th, 2011, 04:25 AM
#9
Re: Differences in Code Generation Between C and C++ Compilers
 Originally Posted by wdolson
Alan: I have a little bit older version pre-C++ conversion that I have been comparing against. I rebuilt the pre-C++ version with the same low level hardware access code as the new version is using. The pre-C++ version works with the hardware, the post C++ conversion version has the errors.
More to Victor's point, when compiling the C++ code, were there any warnings in the compilation? If not, have you set the compiler for the highest warning level that's supported? If you haven't then do so and recompile.
At this point, your problem seems to suggest you have an unsigned/signed issue, data type size issue, struct alignment (if you're using structs) issue, etc. If your compiler issued warnings about signed and unsigned data types, then you need to go over this carefully.
You know what sizes the data types are for the C program. The way you ensure this for a C++ program is to either use static_assert() or if your compiler doesn't support that, a macro that would immediately stop compilation if a data size is not satisfied.
Code:
#define STATIC_ASSERT(cond) { char x____[(cond)?1:0]; }
///..
// Example usage:
STATIC_ASSERT( sizeof(long) == 4 )
STATIC_ASSERT( sizeof(double) == 8 )
STATIC_ASSERT( sizeof(int) == sizeof(long) )
If the long data type is not 4 bytes, double is not 8 bytes, and ints are not the same size as longs, the compilation immediately stops with an error. Usage of this and similar constructs minimized the chance that a "bad" executable is created. You could probably also issue STATIC_ASSERTS to test for alignment, struct sizes, etc.
The program compiles and runs fine. The errors are false positives in tests on the hardware. The program is saying the hardware is failing.
What error indicates that the hardware failed? There must have been some sort of error code returned that indicated failure, and from there you backtrace to see what generated the error, which function sent the error code, etc..
Regards,
Paul McKenzie
-
May 5th, 2011, 08:09 AM
#10
Re: Differences in Code Generation Between C and C++ Compilers
Well, the difference is in the program results. Possibly, old (or/and new) versions of the program have some bugs (like uninitialized varible itc.) which can cause undefined behavior.
Did you try to debug the program and see whether error messages are correct? Just forget about old version and make new version working. You will understand the difference between two versions only after fixing the problem, there is no sence to guess.
-
May 5th, 2011, 08:33 PM
#11
Re: Differences in Code Generation Between C and C++ Compilers
I set the warning level up to level 4 and got almost 200 warnings. Virtually all of those were OK, but I fixed them anyway. 90% of these errors were conversions from int to short, but the value held by the int is always less that 2000.
It is quite possible that there is something that is losing resolution via a cast. However, I'm still wondering why the older version passes these tests and the newer version fails. The two versions only had one real difference between the working and non-working version. I had tried commenting out the change and it still failed.
It's possible something was marginal and just barely working before, but something subtle I did pushed it over the edge into failing.
I'm not able to run the program in the debugger with live hardware because the hardware interface is ISA and the only ISA computers I have don't have VS 2005 installed. However, the guy who converted this program from DOS to Windows added an extensive log file that saves all the variables as they are generated.
I have log files from each run. I recently discussed this with my customer and he gave me some further background on the how the hardware works and gave me some clues to look at upstream from where I'm seeing the problems. I'm analyzing the logs now.
My customer did say that this program has always given them headaches. When I inherited it, it was on version 7.10. The rest of the software package released was 4.x and they were trying to get 5.0 out the door.
Bill
-
May 5th, 2011, 09:10 PM
#12
Re: Differences in Code Generation Between C and C++ Compilers
 Originally Posted by wdolson
I set the warning level up to level 4 and got almost 200 warnings. Virtually all of those were OK, but I fixed them anyway. 90% of these errors were conversions from int to short, but the value held by the int is always less that 2000.
Did you ensure this, or are you assuming this is the case?
Code:
#include <assert.h>
#include <limits.h>
//...
int someValue;
//...
assert( someValue <= SHRT_MAX );
It's possible something was marginal and just barely working before, but something subtle I did pushed it over the edge into failing.
I'm not able to run the program in the debugger with live hardware because the hardware interface is ISA and the only ISA computers I have don't have VS 2005 installed.
Debug remotely. Visual Studio has the option to debug programs on another machine, and the machine need not have Visual Studio installed. All that's necessary is that the machine can be connected to via network or TCP/IP.
There is a program in your Visual Studio bin directory called MSVSMON.EXE. Run this program on the ISA machine. Once you do that, you can debug the program running on that machine from your non-ISA, Visual Studio machine, given that you can connect to the ISA machine.
Regards,
Paul McKenzie
-
May 6th, 2011, 12:10 AM
#13
Re: Differences in Code Generation Between C and C++ Compilers
Yes, this is usual situation in real time programming, when debugging is impossible. Tracing and logging is the way, just continue in this direction.
-
May 6th, 2011, 12:28 AM
#14
Re: Differences in Code Generation Between C and C++ Compilers
I finally tracked it down. It was an extern. For some reason, it was compiling OK, but an array was being filled with zeroes when it was filled with values when it was declared.
I don't know why it was compiling. There was also a place where there was a division by an element of the array, which should have caused a divide by zero error. I'm not sure why that didn't happen.
Thanks for all the help. I will probably use the remote debugger further down the line when I need to do more work on this application.
Bill
-
May 6th, 2011, 04:47 AM
#15
Re: Differences in Code Generation Between C and C++ Compilers
 Originally Posted by wdolson
I finally tracked it down. It was an extern. For some reason, it was compiling OK, but an array was being filled with zeroes when it was filled with values when it was declared.
OK, I'll take a stab at this one:
In one module, did you declare the array with the [] syntax? For example:
and in the extern version, did you do this, or something similar?
Code:
extern double *array;
// or
extern double array[5]; // or some other number
If the extern and the non-extern differ in any way, your application is faulty and is prime for memory corruption or weird behaviour.
The problem is that the different definitions are not picked up by the compiler, since the compiler doesn't do any cross-reference checks for other modules that may have different definition. The linker also doesn't pick it up, because as far as the linker is concerned, the names match (in this case "array"). So what you wind up with is one variable, array, with two different sizes floating around in your app.
I have seen this error before, where the coder uses global array variable and either messes up the array dimensions, or they declare a pointer, thinking that it is the same thing.
I don't know why it was compiling.
Explained above (if your code made the mistake I mentioned).
There was also a place where there was a division by an element of the array, which should have caused a divide by zero error.
No.
The Intel floating point CPU has a divide-by-zero flag that protects the app from shutting down. Instead, the value you get back is a NAN (Not-A-Number). Someone will correct me about the value if I'm wrong, but apps just barfing an exception on divide-by-zero is not the default for the C runtime (you have to set this flag yourself -- I think the function is _control87() or _controlfp()).
Regards,
Paul McKenzie
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|