And bear in mind that the line before the one reported can be in an entirely different file, depending on the order of #includes! I don’t know if this is a problem with modern C preprocessors, but I’ve sometimes had cross-platform problems where someone checked in a header file protected with #ifndef/#define/#endif and no newline at the end. This worked fine on Windows, but made a Solaris-based compiler plotz.
In general, I start fixing reported errors from the top of the file heading downward. Files should be short enough that you can recompile quickly enough that you can make a change and recompile quickly to make sure it worked.
I’m in the habit of commenting all my C/C++ #includes with mentions of what I’m including them for (which comes in handy later when you’re splitting the file up into pieces after it grew to a size where it’s worth breaking up and when turning features on and off during the debugging process). If I’m implementing from an RFC, I tend to include liberal quotations from the RFC as comments in the code.
It takes only a little extra time to do this at the start, and makes program maintenance much easier down the road.
On Linux, handy commands are fuser (for figuring out who’s using that file), strace (to eavesdrop on system calls), ldd (to see which libraries the program is loading), objdump (to peek into object files), size (discover the section sizes of a binary with -A) and strip (to remove the symbol table before shipping). On Win32, get regmon and filemon and use dumpbin (like ldd and nm) and depends (a very thorough ldd for Win32’s amazing webwork of DLLs).
I once ended up having to cope with a system where data of an unknown length was being pumped over the network by a PC that was decoding stock ticker information that came in off a satellite dish. The guy who had written the library to do this had solved the problem by doing a whole lot of read(1) calls— yes, that’s a system call for every single byte coming down the connection. That’s a huge wasteage of CPU.
I did some research on the Internet and found the UNIX Sockets FAQ, where I learned about putting sockets in non-blocking mode, which you by using fcntl() to set the O_NONBLOCK flag on the socket (and don’t forget to do it on the flags that you retrieved via fcntl() first, or you could put the socket in a weird state!). When you do that, read() returns instantly with whatever amount of data is available from the socket. If you need a timeout, use select().
If you don’t want to go into non-blocking mode, you can also use ioctl() with the FIONREAD parameter to find out how many bytes are currently unread on your file descriptor.
Other useful FAQs are the Winsock Programmer’s FAQ, Winsock Development Information, and the Raw IP Networking FAQ.
Cross-platform work can be a headache, and I recommend you do it by engineering a good class library to hide all the differences between platforms from the start and proceeding from there. (At CoVia, I had a File class that had an STL vector of Rogue Wave RWCStrings and understood how do to path arithmetic and the different path formats (UNIX, Windows, UNC, ...) and a Directory subclass that made directory navigation easy. Hint: save on stat() calls by using a mutable structure to store the information in the class.
Under VxWorks, I found that Windows NT and Windows 98 have different ways they treat output redirection. This make rule worked fine on NT:
%.s : %.html sed -e "s/ *</</g" -e "s/> */>/g" $< > $*.tmp binToAsm $*.tmp | sed -e "s#binArray#$(*F)#" > $@ rm $*.tmpbut plotzed on 98. When I changed it to:
%.s : %.html sed -e "s/ *</</g" -e "s/> */>/g" $< > $(subst /,\,$*.tmp) binToAsm $*.tmp | sed -e "s#binArray#$(*F)#" > $(subst /,\,$@) rm $*.tmpeverything worked fine, though I would’ve had to make conditional rules if this were also building on Solaris as well.
I also found that you can’t manipulate multiple rules like that in a single project in VxWorks’ Tornado. Each rule is filed under the target, so if you have one rule for %.s: %.html and another for %.s: %.jpg, you have to add them by hand-hacking the WPJ file and never, ever editing the rule through the GUI again.
GNU make is an excellent tool. I’ve been able to put together some pretty effective build environments using GNU make— I whipped up the one for CoVia from scratch and got it to build on Solaris and Windows. VxWorks also uses it, though on there you have to know how it uses TCL to convert its WPJ files to GNU Makefiles.
I prefer CVS to SourceSafe, for a multitude of reasons, including the fact that SourceSafe has this interesting tendency to corrupt its own database. The modern versions of SourceSafe will let you un-corrupt the database without forcing everyone on the network to log off (most easily performed at the circuit breaker box), but you still have to know to run it every week. By the time the corruption shows, it’s usually already too late. CVS works from the command line, as does SourceSafe, and the CvsGui project is doing quite well. I’m curious as to how well Subversion is working out, and looking forward to Katie (a cross between CVS and NFS) maturing.
Rogue Wave makes some excellent class libraries. Threads.h++ makes threading issues easy to deal with, with guard classes that automatically lock resources at construction time and unlock them as their destructors are called, and I still can’t decide which is more cool: the recursive readers-writer lock or the thread pool that has a queue of functors you can throw into it for processing as threads become available. Tools.h++ is most memorable for its nifty string, date, time, and regular expression classes, as a lot of its other goodies are replicated by the STL. Tools.h++ Professional makes networking very easy— I was able to put together a multithreaded web server very quickly using the classes there. DBtools.h++ has one of the best uses I’ve seen for operator overloading: its classes are designed so you can perform SQL queries using C++ syntax. (The [] operator on a table object gives you a column object reference, operators between columns and other forms of data yield expression objects, and expression objects can be fed to selectors.)
There’s a delightful UNIX utility that lets you watch all the system calls being made. On Solaris, it’s called truss; on Linux, it’s strace. It makes it much easier to see what files and libraries are being accessed and what’s going wrong with a program for which you lack source code. Win32 isn’t quite so helpful, but there are some nifty utilities at Sysinternals Freeware like Filemon, which lets you watch filesystem activity, and Regmon, which lets you watch registry activity. Sysinternals is full of useful information for Win32 developers; any time you have to deal with weird low-level Windows behavior, it’s worth looking the site over.
Cygwin provides Unix utilities that make Win32 a lot more livable; if you use tcsh, you can avoid the problem with command line editing screwing up in insert mode by putting settc im '' and settc ei '' into your .cshrc. Cygwin comes with Perl, but ActivePerl is also available, and effective, without Cygwin.
If you lose the admin password for your NT or Win2K box, there is an Offline NT Password and Registry Editor, and countermeasures [PDF] to this vulnerability. There’s a nice NSA-commissioned study of Windows NT Security Guidelines at Trusted Systems Services.
Copyright © 2001–4 Max Rible Kaehn — All Rights Reserved.