Introduction
Coding in C++ is an art, a passion. Many other languages like Java have absorbed the constructs of C++ because it is elegant. In my article, I shall discuss many styles, practices and discipline of coding C++. I have split the article into mutiple chapters and this chapter is about how to code elegantly to get rid of warnings.
Getting Rid Of Compiler Warnings
Always when you build your project, you must develop the habit of making it free of warnings. It is always a good practice to resolve the warnings because being lazy to resolve them or just being contended that the code just works fine will lead to dangers later. A successful build should be warning free. In this chapter, I'll discuss a few of the common warnings that the visual c++ compiler spits and how to solve them so that we get a successful build. The solution to resolve warnings is not switching it off but almost a slight modification in the code, else it may be a potential threat of a run-time danger. And not all warnings are dangerous at run-time but they are always a black spot.
1. VARIABLE DEFINED BUT NEVER USED
If the variable defined is not used ie not really needed then remove it. But this cannot be done always. Let us understand by example.
void func()
{
long lv;
}
Now take this case. Here we call a method SomeFunc that may throw an exception. If it does, then we catch it to safely handle the situation and just put out a trace message. But we get a warning that 'e' is not used. How do we solve this, simply use the variable as an expression.
void Fun()
{
try
{
SomeFunc();
}
catch(MyException& e)
{
e;
OutputDebugString("Exception Occurred");
}
}
Moral: Always know that you have declared a variable and how and where you use that in your code.
2. VARIABLE NOT INITIALIZED
Many times, we declare int i or long k and directly use in that in loops or in some 'if' statements, and that is disasterous. Always initialize the variable to the best default that the situation demands. An int i need not be always initialized to 0 because may be i am going to do a reverse scan on an array of size 20.
Moral: Always know that you have declared a variable and how and where you use that in your code.
3. SIGNED/UNSIGNED MISMATCH
I have got this warning innumerble times. For example, the natural tendency of a programmer to store a numeric is as an int.
unsigned long GetMyNumber()
{
long lv = 100;
.
.
.
return lv;
}
void main()
{
long x = 10;
long y = 20;
if ( x == GetMyNumber())
{
}
else if ( y == GetMyNumber() )
{
}
}
Change the types of the variables being compared so that the types agree. If not apt for the situation, use an explicit static_cast. The cast operators in C++ is very good style and discipline to follow. In the above case, the compiler casts implicitly and issues a warning because :-
int c = -2;
unsignec int uc = 255;
if ( c < uc )
{
cout << "Less Than";
}
else
{
cout << "Not Less Than";
}
The above case will print not less than.
Moral: Know what the type and content of the variable represents and manipulate them accordingly.
4. MISSIGN RETURN
Consider the code below.
int missingret(int age)
{
if ( age <= 10 )
{
return 1;
}
if ( age > 10 && age <= 50 )
{
return 2;
}
if ( age > 50 && age < 500 )
{
return 3;
}
}
The above logic might be ok for your employee program that says no employee must live more than 500 years. Even though that it is true, the compiler will not believe it and will warn you "what do i return if an employee is 600 years old". We may be sure that the control during the program execution will never reach the end of the function but the compiler is not and we have convince it by giving a return at the end of the function. Ultimately it is the compiler that compiles the code and not us, so better do it if you want to write elegant code this way:-
int missingret(int age)
{
int nRetVal = 0;
if ( age <= 10 )
{
nRetVal = 1;
}
if ( age > 10 && age <= 50 )
{
nRetVal = 2;
}
if ( age > 50 && age < 500 )
{
nRetVal = 3;
}
return nRetVal;
}
Moral: Never assume that an employee will not live more than 500 years. Ensure that all control paths return [process] the correct value and not assume an unknown value at run-time.
5. UNREACHABLE CODE
This is a simple well-known warning.
int func()
{
return 2;
cout << "How can i reach here ??";
}
The cout statement in the above code is not reachable since we return 2 in any case. The above code is simpe snippet that illustrates the problem. We will encounter this in fucntions that have a complex logic involving many loops and decision statements, and in the go, we miss something that results in large code of code unreachable. For example, if a if block was in
Moral: Review the code thoroughly whenever a function has multiple return statements.
6. UNUSED FUCNTION PARAMETERS
It is better to remove the parameter if not really used but has been just put in place for a reason that you do not remember.
int ManipulateString(const std::string& sText, bool b = false)
{
sText.append("_Modified");
return 0;
}
But sometimes in my project, i come across situations where i have to protoype the function with a parameter but that will be really useful only in my next version. In such cases, it syntax works out.
int ManipulateString(const std::string& sText, bool = false)
{
sText.append("_Modified");
return 0;
}
Later
int ManipulateString(const std::string& sText, bool b = false)
{
if ( b == true )
{
sText.append("_Modified");
}
else
{
sText.append("_Modified_New Version");
}
return 0;
}
Moral: Ensure you have a parameter because you need it in the function, now or later. If it's not needed now, delete the name of the function parameter.
7. WARNINGS FROM THIRD PARTY FILES
My God, this has always been a war in my project. We use third party development headers in our project and we get a lot of warnings from those developement headers. On examining the code in the third party header, you may find some of the above warning cases that we discussed above but we are not supposed to change them. In such cases, i follow what Herb Sutter has suggested. Wrap the file with your own version that #include s the original header and selectively turns off the noisy warnings for that scope only, and then #include your wrapper throughout the rest of your project.
#pragma warning(push)
#pragma warning(disable:4512)
#pragma warning(disable:4180)
#include "ThirdParty/TPTrace.h"
#pragma warning(pop)
Conclusion
So in this chapter we have learnt how to rephrase our code a bit and avoid warnings. That makes a reviewer of the code feel the code elegance and you can ensure that he correctly understands what you attempted to do in the code. After all the software business runs that way half the time. In the next chapter, let us see other practices that help us write good code.
"Always write good code. Feel bad to write bad code." - Herb Sutter.
History
� Initial Version � 14 April 2005.
� Updated � 20 April 2005 � Updated comments from readers.