but the Code Wont Compile Funny
There Are Many Ways to Do the Same Thing (at Least In C++)
If you have been using C++ for some years, you will know that there is more than one way to do anything in C++. This also means you have more than one way to get a compilation failure in C++. This blog post is quite ambitious, as I want to do an exposition on how to avoid C++ compilation errors. But to understand how to avoid C++ compilation errors, you need to understand where they come from.
A Compilation failure Comes From the Compiler, Silly
Yes, it does come from the compiler. But what triggered it in the first place is something you – the programmer – did. You gave a C++ program that the compiler couldn't transform to machine code and thus resulted in a compilation failure.
Don't talk in euphemisms you say? Let me give a canonical example of a compilation failure:
void ConvertStringToPasswordForm(char password[]) { while (*password != '\0') *password++ = '*'; }
This function's driver is given below:
int main(int argc, char** argv) { char* password = "MyTopSecretPasswordPublishedInABlog:-)"; ConvertStringToPasswordForm(password); std::cout << "Password :: " << password << std::endl; }
The error message is clear:
error C2440: 'initializing': cannot convert from 'const char [39]' to 'char *'
Aha, it's a const problem you wonder. You change the driver to:
int main(int argc, char** argv) { const char* password = "MyTopSecretPasswordPublishedInABlog:-)"; ConvertStringToPasswordForm(password); std::cout << "Password :: " << password << std::endl; }
But the compiler is adamant. It still did not resolve the compilation failure. Now the cpp compilation error message is:
error C2664: 'void ConvertStringToPasswordForm(char [])': cannot convert argument 1 from 'const char *' to 'char []'
For a while, you consider changing the first function's parameter to const char* to fix the compilation failure but decide against it. As a wonderous C++ programmer, you decide to shut up the compiler:
int main(int argc, char** argv) { const char* password = "MyTopSecretPasswordPublishedInABlog:-)"; ConvertStringToPasswordForm(const_cast<char*>(password)); std::cout << "Password :: " << password << std::endl; }
Does the program compile? Yes! Does it work? NO!
What is the right way to fix this cpp compilation issue? Here it is:
int main(int argc, char** argv) { char password[] = "MyTopSecurePasswordPublishedInABlog:-)"; ConvertStringToPasswordForm(password); std::cout << "Password :: " << password << std::endl; }
It is not enough to pacify the compiler; you need to understand why a program works the way it works. (Try the set of programs here: https://coliru.stacked-crooked.com/a/5e246877801d5263).
Let's Get to the Items Then
1. Understand the language well. Arrays decay to pointers in both C and C++, but not always as can be seen from the above example. One of the most important ways to avoid compilation failures in any language is to understand the language well.
2. Understand that Language grammars change too. Let me explain this with an example:
int main(int argc, char *argv[]) { for (int i = 0; i < 10; ++i) { /*do something */ } int valueof_i = i; return 0; }
I hoped this would work on an old Dev-C++ IDE. It did not. I got the following C++ compilation errors:
The program would be valid because, in prehistoric times, the scope of index variable for a for loop extended outside. So, if you are migrating an old C++ program before the new ISO 'for' scoping was introduced, you will run into CPP compilation issues. In Visual Studio you can turn off conformance (not recommended for new code):
3. IDEs are your friend. Today there is no dearth of good IDEs, both free and paid. Let me give you an example of where IDE helps:
class Example
As soon as I put the opening braces, my trusted Visual Studio 2019 IDE helpfully completes:
class Example
{};
How many times have you forgotten to put that in that semicolon and resulted in a compilation failure? Isn't it great that IDE can fill that in? Additionally, a good IDE gives keyword highlighting, IntelliSense, and context-sensitive help.
4. Use good engineering practices. Assume you are working on a complex program. Use either the bottom-up or top-down approaches (https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design) to code it. Write small functions that are easy to understand and easier to compile. As you write the code, constantly make sure the program is compiling clean.
5. Be extra careful while writing templated code. I know template metaprogramming is Turing complete and it is fun to write metaprograms. I wonder if the compiler writers intended the template errors also to be Turing complete. ? But the recent compilers (those supporting C++17 std and above) are becoming better at pointing errors.
Let me give an example: Here is a code:
template<typename T> class SimpleTemplateUse { private: const T& v; public: SimpleTemplateUse(const T& v) :v(v) {} }; template<typename T> int f(T x) { f(SimpleTemplateUse<T>(x)); }
Instantiating this template as f(0) gave me the following error in my old Dev-C++ IDE:
The same program in VS 2019 gave a sane:
fatal error C1202: recursive type or function dependency context too complex compilation failure error. Much better!
6. Understand the API of a third-party library before trying to use it. This advice is valid for all compiled programming languages that support third-party libraries, not just C++ for avoiding compilation errors. You don't use the win32 API, without knowing where to use HINSTANCE, HANDLE, or HMODULE. Study the details before you delve into complex libraries.
7. If your program is intended to be cross-platform, make the platform-dependent code is well encapsulated under conditional compilations. I was going through the source code of folly recently (https://github.com/facebook/folly) and I see it to be beautifully written. The cross-platform parts are well encapsulated:
#ifndef _WIN32 #define _GNU_SOURCE 1 #include <dlfcn.h>
0 Response to "but the Code Wont Compile Funny"
Enviar um comentário