I've got an old project written in C and I changed the project to compile with the C++ compiler. All modules were renamed .CPP and the /TP flag is set in the Advanced Options to compile as C++.
I thought I would take advantage of the more robust C++ compiler.
I'm getting a number of LNK2019 and LNK2001 errors. Here are a couple of examples:
I also don't know why the compiler is adding a 1 to the end of the file name when creating the object file. The CPP file for the first example is filer3_32.cpp. I cleaned out all the old OBJ files before recompiling. That's not a major issue if the whole thing links OK.
CheckDupLists is in another module in the program that is included in the project. Each module that calls CheckDupLists has an extern declaration for the function. I have double checked and the extern declaration exactly matches the function definition.
The C version compiled without any issues. This should be obvious, I've figured these out before, but this one has me stumped. Any ideas?
Even though you set the compiler to always compile as C++ there might be an extern "C" declaration somewhere .
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.
- Brian W. Kernighan
One of the first things I did was remove all extern "C" references. There were a couple of modules already built as C++ and there were a number of externs declared that way to deal with them. Everything in the collection of projects has been changed from .c to .cpp and all are now compiled as C++. There are a couple of DLLs and several EXEs. The programs that are having the unresolved externals are EXEs. Bill
The reasons for the various link errors were many. In the case of CheckDupLists, there were two modules in the project, one ListSup2_32.cpp and the other LinkSup2_32.cpp. I only noticed the difference when opening ListSup2_32.cpp from different sub-projects appeared to open two different files.
There were also problems with the labyrinth of header files some previous program had set up with a bizarre array of #defines and conditional blocks of externs. Some functions were defined differently in different files and when compiled in C, they happened by chance to go down the right path to compile OK, but when I switched to CPP, this changed some of the conditionals and things got weird. This was the toughest to untangle.
I also found some global data declarations that should never have worked at all. The same global data structure was defined in a couple of files. I don't know why this hasn't caused bugs up until now.
This code is a mess. Has anyone ever seen how spinner controls and list boxes were populated in Windows 2? It's extremely non-intuitive. I've learned to appreciate the more modern Windows libraries much more.
Some functions were defined differently in different files and when compiled in C, they happened by chance to go down the right path to compile OK
In 'C', functions using the same name, but have different parameters are perfectly valid. All 'C' cares about is the name of the function. You can compile all types of junk successfully in 'C' --the issue is that the program created this way exhibits undefined behaviour.
Here is an example:
Code:
int main()
{
int x = sqrt(98, 343, 234324);
}
In the example above, sqrt() is not declared, it takes 3 parameters, and it returns an int. This code compiles and links as 'C' with no errors. When you run it, that's when the weird things happen as the real sqrt() function looks nothing like that. You may get stack corruption errors or other errors.
Some C history -- when 'C' was first introduced, there were no such thing as function prototypes. In other words, you better call the function correctly, including assigning the return value to the correct type, else you would have a compiled program that has huge bugs.
Then came along the idea of the function prototype in 'C' to alleviate this issue. However, 'C' still accepts the stuff I posted above -- you can call any function any way you want (if you haven't declared it with a prototype), with the danger of runtime bugs if you didn't call the function correctly.
but when I switched to CPP, this changed some of the conditionals and things got weird. This was the toughest to untangle.
This is the big difference -- C++ checks prototypes since overloaded functions are valid in C++. If you're taking a C program written without using prototypes for functions, or generally coded by a hard-core C programmer who didn't care one whit about C++, then you will get these issues when converting from C to C++.
I also found some global data declarations that should never have worked at all. The same global data structure was defined in a couple of files. I don't know why this hasn't caused bugs up until now.
See above about what 'C' can do that C++ cannot and was not designed to do.
In 'C', functions using the same name, but have different parameters are perfectly valid. All 'C' cares about is the name of the function. You can compile all types of junk successfully in 'C' --the issue is that the program created this way exhibits undefined behaviour.
Here is an example:
Code:
int main()
{
int x = sqrt(98, 343, 234324);
}
In the example above, sqrt() is not declared, it takes 3 parameters, and it returns an int. This code compiles and links as 'C' with no errors. When you run it, that's when the weird things happen as the real sqrt() function looks nothing like that. You may get stack corruption errors or other errors.
Yes. Most of the functions were double prototyped, one set with no arguments and another with extern "C" for the modules already compiled in C++. But some functions were only prototyped with no arguments. There were about 8 different conditional compile flags that could be set and many were nested in the header files. It took me about an hour per header file to straighten it all out.
Some C history -- when 'C' was first introduced, there were no such thing as function prototypes. In other words, you better call the function correctly, including assigning the return value to the correct type, else you would have a compiled program that has huge bugs.
Then came along the idea of the function prototype in 'C' to alleviate this issue. However, 'C' still accepts the stuff I posted above -- you can call any function any way you want (if you haven't declared it with a prototype), with the danger of runtime bugs if you didn't call the function correctly.
I started programming in C just as prototyping was beginning to catch on in the late 1980s.
This is the big difference -- C++ checks prototypes since overloaded functions are valid in C++. If you're taking a C program written without using prototypes for functions, or generally coded by a hard-core C programmer who didn't care one whit about C++, then you will get these issues when converting from C to C++.
See above about what 'C' can do that C++ cannot and was not designed to do.
Regards,
Paul McKenzie
This is one of the reasons I changed the code to CPP files so I could get stronger prototyping checks by the compiler. The first version of this code was written before C++ existed. Even the C standard libraries hadn't been completely established yet. There are some home made string functions in there that could easily be replaced with standard C library calls. I've been replacing them if I'm working on that section of the code, but I haven't gone through and changed them all wholesale yet. That will wait for the replacement of the UI. The parts of internal code that will be saved are going to get brought up to date as much as I can. Bill
Bookmarks