Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A free tool to check C/C++ source code against a set of coding standards?
I am starting a c++ project involving several people I have no direct access to. We agreed on a coding style guide, which e.g. defines the casing for class members depending on the accessibility (i.e. privates in pascal case, publics and protecteds in camel case. Please, don't start discussions about the style guide. I had enough. Thank you.).
What I want to do now is to generate some reporting of style guide violations. I don't want to enforce the style guide, e.g. at commit, but I want to provide a tool which each developer can use to see where his/her code violates the style guide (if he/she wants to check it).
Do you know a tool which can do the Job?
(It needs to be able to understand some C++, e.g. to detect the accessibility of class members.)
well, you could run your code through AStyle or Uncrustify on commit, which would at least re-format bad code to some standard. I find that's the majority problem with code commits and standards - if you reformat after commmit, it shows up as a lot of delta changes that are entirely trivial.
Otherwise, check the other SO answer.
Style guides tends to be company-specific, and one has to write company-specific checks to achieve them.
My company offers customizable C++ style checkers, in which one can check for deprecated idioms by syntax, check that variables and types have certain properties, or verify that certain commands occur in certain orders locally. These checkers use C++ dialect precise parsers on the source code. The customization isn't easy; you need the underlying engine and some knowledge of parsing C++ programs.
It is possible to write rules that check for layout, but it is a lot of unrewarding work, and resolving such complaints isn't a productive use of programmer resource IMHO. And if you aren't going to enforce your style, why are you annoying the programmer with complaints at all? IT seems easier (as another poster noted) to simply run a layout-formatter that produces the right result at no cost to the programmer.
One of the issues with generic formatters is that being language-imprecise, they may misinterpret the source code and sometimes break it as they format, leading to compilation errors, debugging and wasted time. We also offer C++ Formatters to accomplish the formatting using the same language precise parsers as the style checker; they can't break your code during reformatting.
I've been successfully using the vera++ tool to do this for our projects. I've wrote a number of rules (in TCL) to adopt our company style guidelines. It was a bit painful, until I came around all the false positives reported from my checks. At least it's working well now and I have integrated the reports to the Jenkins build analysis.
The reports can also be easily adopted to a custom error analysis in the Eclipse IDE.
For a language like C++ the existence of a standard is a must. And good compilers try their best (well, most of the good compilers, at least) to comply. Many compilers have language extensions, some of which are allowed by the standard, some of which are not. Of the latter kind 2 examples:
gcc's typeof
microsoft's compilers allow a pure virtual function declaration to have both a pure-specifier(=0) and a definition (which is prohibited by the standard - let's not discuss why, that's another topic:)
(there are many other examples)
Both examples are useful in the following sense: example1 is a very useful feature which will be available in c++0x under a different name. example2 is also useful, and microsoft has decided not to respect the ban that made no sense.
And I am grateful that compilers provide language extensions that help us developers in our routine. But here's a question: shouldn't there be an option which, when set, mandates that the compiler be as standards compliant as it can, no matter whether they agree with the standard or not. For example visual studio has such an option, which is called disable language extensions. But hey, they still allow example2.
I want everyone to understand my question correctly. It is a GREAT thing that MSVC allows example2, and I would very much like that feature to be in the standard. It doesn't break any compliant code, it does nothing bad. It just isn't standard.
Would you like that microsoft disable example2 when disable language extensions is set to true? Note that the words microsoft, example2, etc. are placeholders :)
Why?
Again, just to make sure. The crucial point is: Should a compiler bother to provide a compliant version (optionally set in the settings)(in its limits, e.g. I am not talking about export) for a certain feature when they provide a better alternative that is not standard and is perhaps even a superset of the standard, thus not breaking anything.
Standards compliance is important for the fundamental reason that it makes your code easier to maintain. This manifests in a number of ways:
Porting from one version of a compiler to another. I once had to post a 1.2 million-LOC app from VC6 to VC9. VC6 was notorious for being horribly non-Compliant, even when it was new. It allowed non-compliant code even on the highest warning levels that the new compiler rejected at the lowest. If the code had been written in a more compliant way in the first place, this project wouldn't (shouldn't)have taken 3 months.
Porting from one platform to another. As you say, the current MS compilers have language extensions. Some of these are shared by compilers on other platforms, some are not. Even if they are shared, the behavior may be subtly different. Writing compliant code, rather that using these extensions, makes your code correct from the word go. "Porting" becomes simply pulling the tree down and doing a rebuild, rather than digging through the bowels of your app trying to figure out why 3 bits are wrong.
C++ is defined by the standard. The extensions used by compilers changes the language. New programmers coming online who know C++ but not the dialect your compiler uses will get up to speed more quickly if you write to Standard C++, rather than the dialect that your compiler supports.
First, a reply to several comments. The MS VC extension in question is like this:
struct extension {
virtual void func() = 0 { /* function body here */ }
};
The standard allows you to implement the pure virtual function, but not "in place" like this, so you have to write it something like this instead:
struct standard {
virtual void func() = 0;
};
void standard::func() { ; }
As to the original question, yes, I think it's a good idea for the compiler to have a mode in which it follows (and enforces) the standard as accurately as possible. While most compilers have that, the result isn't necessarily as accurate a representation of the standard as you/I would like.
At least IMO, about the only answer to this is for people who care about portability to have (and use) at least a couple of compilers on a regular basis. For C++, one of those should be based on the EDG front-end; I believe it has substantially better conformance than most of the others. If you're using Intel's compiler on a regular basis anyway, that's fine. Otherwise, I'd recommend getting a copy of Comeau C++; it's only $50, and it's the closest thing to a "reference" available. You can also use Comeau online, but if you use it on a regular basis, it's worth getting a copy of your own.
Not to sound like an EDG or Comeau shill or anything, but even if you don't care much about portability, I'd recommend getting a copy anyway -- it generally produces excellent error messages. Its clean, clear error messages (all by themselves) have saved enough time over the years to pay for the compiler several times over.
Edit: Looking at this again, some of the advice is looking pretty dated, especially the recommendation for EDG/Comeau. In the three years since I originally wrote this, Clang has progressed from purely experimental to being quite reasonable for production use. Likewise, the gcc maintainers have (IMO) made great strides in conformance as well.
During the same time, Comeau hasn't released a single new version of their compiler, and there's been a new release of the C++ standard. As a result, Comeau is now fairly out of date with respect to the current standard (and the situation seems to be getting worse, not better -- the committee has already approved a committee draft of a new standard that is likely to become C++14).
As such, although I recommended Comeau at that time, I'd have difficulty (at best) doing so today. Fortunately, most of the advantages it provided are now available in more mainstream compilers -- both Clang and gcc have improved compliance (substantially) as outlined above, and their error messages have improved considerably as well (Clang has placed a strong emphasis on better error messages, almost from its inception).
Bottom line: I'd still recommend having at least two compilers installed and available, but today I'd probably choose different compilers than I did when I originally wrote this answer.
"Not breaking anything" is such a slippery slope in the long run, that it's better to avoid it altogether. My company's main product outlived several generations of compilers (first written in 1991, with RW), and combing through compiler extensions and quiet standards violations whenever it was the time to migrate to a newer dev system took a lot of effort.
But as long as there's an option to turn off or at least warn about 'non-standard extension', I'm good with it.
34, 70, 6.
I would certainly want an option that disables language extensions to disable all language extensions. Why?
All options should do what they say they do.
Some people need to develop portable code, requiring a compiler that only accepts the standard form of the language.
"Better" is a subjective word. Language extensions are useful for some developers, but make things more difficult for others.
I think that it's critical that a compiler provide a standards-only mode if it wants to be the primary one used while developing. All compilers should, of course, compile standards compliant code, but it's not critical they they don't extend if they don't think of themselves as the primary compiler -- for example, a cross-compiler, or a compiler for a less popular platform that is nearly always ported to, rather than targeted.
Extensions are fine for any compiler, but it would be nice if I had to turn them on if I want them. By default, I'd prefer a standards-only compiler.
So, given that, I expect MSVC to be standards-only by default. The same with gcc++.
Stats: 40, 90, 15
I think standards compliance is very important.
I always consider source code is more for the human readers than for the machine(s). So, to communicate programmer's intention to the reader, abiding the standard is like speaking a language of lowest common denominator.
Both at home and work, I use g++, and I have aliased it with the following flags for strict standard compliance.
-Wall -Wextra -ansi -pedantic -std=c++98
Check out this page on Strict ANSI/ISO
I am not a standards expert, but this has served me well. I have written STL-style container libraries which run as-is on different platforms, e.g. 32-bit linux, 64-bit linux, 32-bit solaris, and 32-bit embedded OSE.
Consider indicators on cars (known as "turn signals" in some jurisdictions); they are a reliable way to determine which direction someone's going to turn off a roundabout... until just one person doesn't use them at all. Then the whole system breaks down.
It didn't "hurt anyone" or obviously "break anything" in IE when they allowed document.someId to be used as a shortcut for document.getElementById('someId').... however, it did spawn an entire generation of coders and even books that consequently thought it was okay and right, because "it works". Then, suddenly, the ten million resulting websites were entirely non-portable.
Standards are important for interoperability, and if you don't follow them then there's little point in having them at all.
Standards-compliance hounds may get hated for "pedanticism" but, really, until everybody follows suit you're going to have portability and compatibility problems for ever.
How important standards-compliance is depends on what you are trying to achieve.
If you are writing a program that will never be ported outside of its current environment (especially a program that you're not planning to develop/support for a long time) then it's not very important. Whatever works, works.
If you need your program to remain relevant for a long time, and be easily portable to different environments, than you will want it to be standards compliant, since that's the only way to (more or less) guarantee that it will work everywhere.
The trick, of course, is figuring out which situation you are actually in. It's very common to start a program thinking it is a short-term hack, and later on find that it's so useful that you're still developing/maintaining it years later. In that situation your life will be much less unpleasant if you didn't make any short-sighted design decisions at the beginning of the program's lifetime.
I have this classic question of how should the C++ Standard (I mean the actual official document of the finalized ones) e.g. C++98, C++03 be used to learn and teach C++. My idea is only from the point of view of an average C++ user and not from the point of view of the language lawyers or someone who wishes to be in the Standards committee, compiler writers and so on.
Here are my personal thoughts:
a) It is aweful place to start learning C++. Books like "C++ in a Nutshell", "The C++ programming Language" etc do a very good job on that front while closely aligning with the Standard.
b) One needs to revert to the Standard only when
a compiler gives a behavior which is not consistent with what the common books say or,
a certain behavior is inconsistent across compilers e.g. GCC, VS, Comeau etc. I understand the fact that these compilers could be inconsistent is in very few cases / dark corners of the language e.g. templates/exception handling etc. However one really comes to know about the possible different compiler behaviors only when either one is porting and/or migrating to a different environment or when there is a compiler upgrade e.g.
if a concept is poorly explained / not explained in the books at hand e.g. if it is a really advanced concept
Any thoughts/ideas/recommendation on this?
The C++ language standard would be an absolutely terrible place to start learning the language. It is dense, obtuse, and really long. Often the information you are looking for is spread across seven different clauses or hidden in a half of a sentence in a clause completely unrelated to where you think it should be (or worse, a behavior is specified in the sentence you ignored because you didn't think it was relevant).
It does have its uses, of course. To name a few,
If you think you've found a bug in a compiler, it's often necessary to refer to the standard to make sure you aren't just misunderstanding what the specified behavior is.
If you find behavior that is inconsistent between compilers, it's handy to be able to look up which is correct (or which is more correct), though often you'll need to write workarounds regardless.
If you want to know why things are the way they are, it is often a good reference: you can see how different features of the language are related and understand how they interact. Things aren't always clear, of course, but they often are. There are a lot of condensed examples and notes demonstrating and explaining the normative text.
If you reference the C++ standard in a post on Stack Overflow, you get more a lot more upvotes. :-)
It's very interesting to learn about the language. It's one thing to write code and stumble through getting things to compile and run. It's another thing altogether to go and try to understand the language as a whole and understand why you have to do things a certain way.
The standard should be used to ensure portability of code.
When writing basic c++ code you shouldn't need to refer to the standards, but when using templates or advanced use of the STL, reference to the standard is essential to maintain compatibility with more than one compiler, and forward compatibility with future versions.
I use g++ to compile my C++ programs and there I use the option -std=c++0x (earlier, -std=c++98) to make sure that my code is always standard compliant. If I get any warning or error regarding standard compliance, I research on that to educate myself and fix my code.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm having a debate with a friend and we're wondering why so many open source projects have decided to go with C instead of C++. Projects such as Apache, GTK, Gnome and more opted for C, but why not C++ since it's almost the same?
We're precisely looking for the reasons that would have led those projects (not only those I've listed but all C projects) to go with C instead of C++. Topics can be performance, ease of programming, debugging, testing, conception, etc.
C is very portable, much more than C++ was 10 years ago.
Also, C is very entrenched in the Unix tradition. Read more in 'The Art of Unix Programming', about Unix and OO in general, and about specific languages on unix (including C and C++).
There are numerous counter examples: everything based on Qt for one.
Also, on my Debian testing system:
edd#ron:~$ apt-cache rdepends libstdc++6|wc -l
4101
So that's 4101 packages depending on the basic C++ library. For comparison, I get about 14,982 for libc6 or roughly 3.6 as many. But it is not if there aren't any C++ projects in Open Source land.
Edit: Thinko on my part: as the C++ packages also depend on libc6, the ratio really is
(14982 - 4101)/4101 = 2.65
so there are roughly 2 1/2 times as many packages implemented in C than there are in C++.
Eric Raymond's wonderful book "The Art of Unix Programming" has some reflections on this issue (the whole book is well worth reading in either the paper or free online editions, I'm just pointing to the relevant section -- Eric was involved with the coining and introduction of the term "open source", and is always well worth reading;-0).
Summarizing that section, Raymond claims that "OO languages show some tendency to suck programmers into the trap of excessive layering" and Unix programmers (and by extension open-source programmers) resist that trap of "thick glue".
Later in the book, you find some considerations specifically about C++, such as "It may be that C++'s realization of OO is particularly problem-prone". Whether you agree or not, the whole text is well worth reading (I can hardly do it justice here!-), and rich with bibliography pointing you to many other relevant studies and publications.
Linus Torvalds has ranted several times on the topic of C++ -- he uses C for git, and of course the Linux kernel is mostly C:
on C++ and git (warning: don flame-retardant first)
an interview with Linus from 1998
You can easily find more of these, and while it's in his nature to get a bit flamey about these things, there are some valid points.
One of the more interesting (from where I'm sitting, anyway) is the observation that C++ compilers and libraries were (and to some degree are) a lot more buggy than the corresponding C compilers. This stands to reason given the relative complexities of the two languages.
It smells a little of "not invented here" (NIH) syndrome, but when you have the entire Linux kernel developer base, you can sometimes afford to reinvent things "The Right Way".
A lot of the projects started before C++ was standardized, so C was the obvious choice and a change later would be hard. C was standardized about a decade before C++, and has been more nearly portable for even longer. So, it was largely a pragmatic decision at the time, inspired in part by the Unix heritage of using C for most code.
C++ is a mess. It is overly complicated language, so complicated that only few people can say that they know all the bits. And fewer compilers which really complies to C++ standard.
So I think the reason is simplicity and portability.
If you want higher-level and object-oriented programming, then I think C++ is just competed with others like Python. (Note that I programmed in C++ few years, it's fast and has some features from higher-level languages that speeds up development, no offence.)
I have worked on a few C++ projects in my time, all of which have ended in tears one way or the other. At the most fundamental level, the truth is that people can't be trusted. They can't be trusted to write good code, they can't be trusted to debug it, and they certainly can't be trusted to understand it when they have to come back and modify it again weeks/months later.
C code doesn't have a lot of the weird stuff in C++ that makes it hard to debug (constructors/destructors, anything that happens with static global objects during cpp_initialize() time, etc.). That just makes it easier to deal with when developing and maintaining a big project.
Maybe I'm a luddite, but every time someone says "C++" around me I get shivers.
Some people have mentioned portability, but in this day, the portability of C++ isn't much of an issue (it runs on anything GCC runs on, which is essentially anything). However, portability is more than just architecture-to-architecture or OS-to-OS. In the case of C++, it includes compiler-to-compiler.
Let's discuss ABI, or Application Binary Interface. This basically means "how your code translates into assembly." In C, when you write:
int dostuff(const char *src, char *dest);
You know that you're making a symbol in your object file called _dostuff (C global names are all prefixed by an underscore in the resultant assembly). But in C++, when you write this:
int dostuff(const char *src, char *dest);
int dostuff(const char *src, char *dest, size_t len);
Or even:
int dostuff(std::string src, std::string dest);
All bets are instantly off. You now have two distinct functions, and the compiler has to make each, and has to give each a unique name. So C++ allows (where I believe C doesn't) name mangling, which means those two functions might get translated to _dostuff_cp_cp and _dostuff_cp_cp_s (so that each version of the function that takes a different number of arguments has a different name).
The problem with this is (and I consider this a huge mistake, even though it's not the only problem with cross-compiler portability in C++) that the C++ standard left the details of how to mangle these names up to the compiler. So while one C++ compiler may do that, another may do _cp_cp_s_dostuff, and yet another may do _dostuff_my_compiler_is_teh_coolest_char_ptr_char_ptr_size_t. The problem is exacerbated (always find a way to sneak this word into anything you say or write) by the fact that you have to mangle names for more than just overloaded functions - what about methods and namespaces and method overloading and operator overloading and... (the list goes on). There is only one standard way to ensure that your function's name is actually what you expect it to be in C++:
extern "C" int dostuff(const char *src, char *dest);
Many applications need to have (or at least find it very useful to have) a standard ABI provided by C. Apache, for example, couldn't be nearly as cross-platform and easily extensible if it was in C++ - you'd have to account for the name mangling of a particular compiler (and a particular compiler version - GCC has changed a few times in its history) or require that everyone use the same compiler universally - which means that, every time you upgrade your C++ compiler with a backwards incompatible name-mangling scheme, you have to recompile all your C++ programs.
This post turned into something of a monster, but I think it illustrates a good point, and I'm too tired to try to trim it down.
As someone who dislikes C++ and would pick C over it any day, I can at least give you my impressions on the topic. C++ has several attributes that make it unappealing:
Complicated objects. C++ has tons of ability to speed up OO, which makes the language very complex.
Nonstandard syntax. Even today most C++ compilers support quirks that make ensuring successful and correct compilation between compilers difficult.
Nonstandard libraries. Compared to C libraries, C++ libraries are not nearly as standardized across systems. Having had to deal with Make issues associated with this before I can tell you that going with C is a big time saver.
That said, C++ does have the benefits of supporting objects. But when it comes down to it, even for large projects, modularity can be accomplished without objects. When you add in the fact that essentially every programmer who might contribute code to any project can program C, it seems hard to make the choice to go with anything else if you need to write your code that close to the metal.
All that said, many projects jump over C++ and go to languages like Python, Java, or Ruby because they provide more abstraction and faster development. When you add in their ability to support compiling out to/loading in from C code for parts that need the performance kick, C++ loses what edge it could have had.
If you look at recent open source projects, you'll see many of them use C++. KDE, for instance, has all of its subprojects in C++. But for projects that started a decade ago, it was a risky decision. C was way more standardized at the time, both formally and in practice (compiler implementations). Also C++ depends on a bigger runtime and lacked good libraries at that time. You know that personal preference plays a big role in such decision, and at that time the C workforce in UNIX/Linux projects was far bigger than C++, so the probability that the initial developer(s) for a new project were more comfortable with C was greater. Also, any project that needs to expose an API would do that in C (to avoid ABI problems), so that would be another argument to favor C.
And finally, before smart pointers became popular, it was much more dangerous to program in C++. You'd need more skilled programmers, and they would need to be overly cautions. Although C has the same problems, its simpler data structures are easier to debug using bounds checking tools/libraries.
Also consider that C++ is an option only for high-level code (desktop apps and the like). The kernel, drivers, etc. are not viable candidates for C++ development. C++ has too much "under the hood" behavior (constructor/destructor chains, virtual methods table, etc) and in such projects you need to be sure the resulting machine/assembly code won't have any surprises and doesn't depend on runtime library support to work.
One important aspect in addition to others that will doubtless be mentioned is that C is easier to interface with other languages, so in the case of a library intended to be widely useful, C may be chosen even nowadays for this purpose.
To take examples I am familiar with, the toolkit GTK+ (in C) has robust OCaml bindings, while Qt and Cocoa (respectively in C++ and Objective C) only have proof-of-concepts for such bindings. I believe that the difficulty to interface languages other than C with OCaml is part of the reason.
One reason might be that the GNU coding standards specifically ask you to use C. Another reason I can think of is that the free software tools work better with C than C++. For example, GNU indent doesn't do C++ as well as it does C, or etags doesn't parse C++ as well as it parses C.
I can list a couple more reasons
C code produces more compact object
code. Try to compile 'Hello World'
as C and C++ program and compare the
size of the executable. May not be too relevant today but definitely was a factor 10+ years ago
It is much easier to use dynamic
linking with C programs. Most of
the C++ libraries still expose entry
points through C interface. So instead of writing a bridge between C++ and C why not to program the whole thing in C?
First of all, some of the biggest open source projects are written in C++: Open Office, Firefox, Chrome, MySQL,...
Having said that, there are also many big projects written in C. Reasons vary: they may have been started when C++ was not standardized yet, or the authors are/were more comfortable with C, or they hoped that the easier learning curve for C would attract more contributors.
If correctly implemented C is very fast and very portable and the compilers are there
C++ is different for each compiler available, the libraries dont agree, the standards donĀ“t match.
You can read Dov Bulka to find what not to do in cpp, you can read tesseract ocr at Google code, you can read lots of things - most of which depend on where you are to determine which code linguistic is superior. Where did you read that c has more source code up in open source than cpp? Well of course you read that in a c forum. That's where. Go to some other programming linguistic. Do the same search, you will find that that code has more open source.
I'm currently in the process of learning C++, and because I'm still learning, I keep making mistakes.
With a language as permissive as C++, it often takes a long time to figure out exactly what's wrong -- because the compiler lets me get away with a lot. I realize that this flexibility is one of C++'s major strengths, but it makes it difficult to learn the basic language.
Is there some tool I can use to analyze my code and make suggestions based on best practices or just sensible coding? Preferably as an Eclipse plugin or linux application.
Enable maximum compiler warnings (that's the -Wall option if you're using the Gnu compiler).
'Lint' is the archetypical static analysis tool.
valgrind is a good run-time analyzer.
I think you'd better have some lectures about good practices and why they are good. That should help you more than a code analysis tool (in the beginning at least).
I suggest you read the series of Effective C++ and **Effective STL books, at least. See alsot The Definitive C++ Book Guide and List
For g++, as well as turning on -Wall, turn on -pedantic too, and prepare to be suprised at the number of issues it finds!
Tool support for C++ is quite bad compared to Java, C#, etc. because it does not have a context-free grammar. In fact, there are parts of the C++ grammar that are undecidable. Basically, that means that understanding C++ code at the syntactic level requires implementing pretty much a compiler front end with semantic analysis. C++ cannot be parsed into an AST independently of semantic analysis, and most code analysis tools in IDEs, etc. work at the AST level. This is part of the tradeoff you make in exchange for the flexibility and backwards compatibility of C++.
Turning on all compiler warnings (at least initially) and then understanding what they mean, how to fix the problems highlighted and which of the warnings represent genuine constructs that compiler writers might consider ambiguous is a good first step.
If you need something more heavy duty, you could try PC-Lint if you're on Windows, which is still one of the best lint tools for C++. Just keep in mind that you'll need to configure these tools to reflect your coding style, otherwise you'll get swamped with warnings and won't be able to see the wood for the trees. Yes, it costs money and it's probably a bit overkill if you're not doing C++ on a "getting paid for it" level, but I find it invaluable.
There is as list of static code analysis tools at wikipedia.
But warnings are generally good but one problem with enabling all warnings with pedantic and Wall is the number of warnings you might get from including headers that you have no control over, this can create a lot of noise. I prefer to compile my own software with all warnings enabled though. As I program in linux I usually do like this:
Put the external headers I need to include in a separate file, and in the beginning of that file before the includes put:
#pragma GCC system_header
And then include this file from your code. This enables you to see all warnings from your own code without it being drowned in warnings from external code. The downside is that it's a gcc specific solution, I am not aware of any platform independent solution to this.
lint - there are lots of versions but if you google for lint you should find one that works. The other thing to do is turn on your compiler warnings - if you are using gcc/g++ the option is -Wall.
You might find CppChecker helpful as a plugin for Eclipse that supports gcc/PC lint.
I think that really what you need to learn here is how to debug outside of an IDE. This is a valuable skill in my opinion, since you will no longer require such a heavy toolset to develop software, and it will apply to the vast majority of languages you already know and will ever learn.
However, its a difficult one to get used to. You will have to write code just for debugging purposes, e.g. write checks after each line not yet debugged, to ensure that the result is as expected, or print the values to the console or in message boxes so that you can check them yourself. Its tedious but will enable you to pick up on your mistakes more easily, inside or outside of an IDE.
Download and try some of the free debugging tools like GDB too, they can help you to probe memory, etc, without having to write your own code.