In order not to postpone the matter in a “long box”, I will continue the story about my experience of using static code analyzers. (Start
here and
here ).
Having tried Klocwork, I tried to interest the management in it, however the price of 30 thousand euros served as the main stopping criterion, everything else was no longer important.
However, someone suddenly remembered that once the company had already acquired a license for some kind of code analyzer. This analyzer was PC-Lint. It turned out that no one uses it (having read to the end, you will understand why), so they gave me the license supposedly to play, if interested.
Well, the system turned out to be the complete opposite of Klocwork. Run from the command line, all settings via parameters or configuration file, the list of files for analysis must be prepared manually. True, there was some kind of integration with Visual Studio, which, however, only allowed to avoid creating a list of files. Configuration files still needed to be written "hands" in a text editor.
')
The output of the results is in a text file. When you start from Visual Studio, go to the studio console, from where you could click to the location of the alleged problem by clicking (it is already easier!).
The main problem of PC-Lint is the number of messages. On a relatively small project, he with the default settings gave out more than 23 thousand comments! Having spent a couple of days on viewing and “turning off” 34 of the most frequent and at the same time non-critical class of problems, I managed to reduce the total number of comments to five and a half thousand!
And of course, in such a heap, several really important notes can be easily lost, indicating a real buffer overflow or the use of an uninitialized variable.
And for this reason, those who bought it stopped using the tool. I also stopped using it, having spent several days digging into thousands of warnings, finding, however, a couple of real critical problems and slightly improving the style of the code.
You can only turn off all messages of a certain type, there is no possibility to mark one specific message as false positive.
Of course, there is no tracking from build to build. You can only focus on the total number of messages.
Problems found in the header files are duplicated each time this file is connected. If a file is connected ten times, then all ten times PC-Lint will display messages about all problems found inside. And if you consider that he easily finds problems even in the files of the studio itself, especially in the implementation of STL containers ...
At the same time, the way in which the problem arises is also not shown in any way. Those. for example, he can report that an uninitialized variable can be used at a given place, but under what conditions it occurs, one has to guess himself (unlike Klocwork, which shows the full path from the beginning of the function to the problem point through all the branchings).
And to top it off - it only works locally. When working in a team, there is no way to easily and quickly report other problems found (only copy-paste text, alas), as there is no possibility of launching by all participants (unless, of course, each participant is purchased a separate license).
There are, of course, the PC-Lint and advantages.
The number of messages can, under certain conditions, be considered a plus. Despite the fact that most of the messages belong to the style and almost never indicate a potential problem, it is necessary to recognize that almost every message has a drop of common sense. And if (theoretically) fix everything that PC-Lint proposes to fix, the code will clearly become better, clearer and more readable. But, as someone said on the Internet, “I want to program in C, not Lint!”.
An example of a “cosmetic” note:
It was:
calib_offset = (int32)(full_offset / full_gain * 100000);
PC-Lint here sees the ambiguity of reading: a / b * c - is (a / b) * c or a / (b * c)?
Accordingly, it became:
calib_offset = (int32)( (full_offset / full_gain) * 100000);
In my opinion, readability has increased!
If the project starts from scratch and is not too large, then with a certain desire it is possible to achieve the “Zero Problems” approach from PC-Lint. If, at the time of the first launch, the project is close to completion, then “Zero Problems” will be almost impossible to achieve.
Of the other advantages, I can highlight the following:
- a very good description of each warning issued (they are all in a separate large PDF document; it is naturally impossible to automatically switch to the description from the studio);
- a very large set of rules, for example, there are rules written in both Myers’s “Effective C ++” books;
- flexible settings - you can turn on and off each rule individually;
- well finds real problems (it is difficult only to find them among the abundance of other messages);
- the price is much cheaper than other options ($ 389 for an unlimited license).
And finally - a pair of really found problem areas:
It was:
switch (SocketID) { case SOCKETID_1: case SOCKETID_2: break; case SOCKETID_3: doSomething(); break; case SOCKETID_4: doSomethingElse(); case SOCKETID_5: doSomethingElseSimilar(); case SOCKETID_6: doAnotherThing(); break; default: return ERR_SERVICE_NOT_SUPPORTED; }
It became:
switch (SocketID) { case SOCKETID_1: case SOCKETID_2: break; case SOCKETID_3: doSomething(); break; case SOCKETID_4: doSomethingElse(); break; case SOCKETID_5: doSomethingElseSimilar(); break; case SOCKETID_6: doAnotherThing(); break; default: return ERR_SERVICE_NOT_SUPPORTED; }
If someone didn't notice, the word break was missed twice;
void main_task(void *p_arg) { int status;
A note to this piece of code is rather stylistic - “The value of the status variable is not used anywhere”, but, in my opinion, not so meaningless — such code creates a false certainty that the result of the memory_init function is taken into account somewhere, but this is not the case.
And it is much more “honest" to rewrite the code like this, without declaring an unused variable and obviously discarding the result.
void main_task(void *p_arg) {
Of course, it would be more correct to check the result and perform the necessary actions in case of failure - but ... this is good when the project is at an early stage, and changing the architecture of the application is still quite easy, and not when the project has already been completed, and in this place the handling of exceptional situations It was not originally laid architecturally (You can check the result, and then what? Where to put it then, if it signals failure, and the calling function does not have an exception handling mechanism?).
And it is precisely for this purpose that a static code analyzer is needed, which is launched regularly (ideally, after each build!), Along with the requirement “Zero warnings from the analyzer”.
Of course, no analyzer will replace a competent developer, code review and other techniques and development management techniques. However, it can definitely make life easier for the whole team with proper use!