Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Mar02: C Programming


Mar02: C Programming

Al is DDJ's senior contributing editor. He can be contacted at [email protected].


I'll open this month's column with a farewell to an old friend. Peter Hutchinson is leaving Dr. Dobb's Journal after a long association as publisher and member of management. Like most writers, I am suspicious of publishers, and like most programmers, I am disdainful of managers. Peter is the exception in both cases. As a reader, you wouldn't know about Peter unless you took time to read his name in tiny print on that list of employees buried inside the book. But his contributions to and influence on what you have read and enjoyed for the past many years are substantial. For me, that list will always have a gaping hole where Peter's name once was. The magazine itself will not be the less for his departure. He built too good an organization for that to happen; our quality is his legacy and our endurance his monument. Looking back, I realize that being able to visit with Peter and his delightful wife Neva is one of the main reasons I traveled cross country to attend all those otherwise dull company parties all those many years. He carries the affection, respect, and good wishes of all of us wherever his fortunes may carry him.

Fixing the Waves

Last month's column described a library of classes that implement audio waveform playback and recording on the Win32 platform. This month I make some minor repairs to those classes. There are two reasons for these changes. First, Windows XP has minor differences between its wave processing API and those of other versions of Win32, differences that uncovered an insidious bug in my code. Second, the next version of Visual C++ draws somewhat closer than its predecessors to the C++ Standard specification, and I had to get compliant.

The issue with XP was a puzzle. My audio application plays waveform audio when run on Windows 98 and ME. But when I copied the executable binary to an XP system and ran it, the playback operation produced nothing but silence and locked up the application. As reported last month, I built my classes by referring to the code in Tim Kientzle's and Charles Petzold's books, so my first test was to see if their programs work under XP. They do, so the problem had to be related to how I wrote my program, which, of course, it was.

This problem was a disaster in waiting and is a major lesson to be learned. I originally planned to complete the application in time for the annual meeting of the International Association of Jazz Educators (http://www.iaje.org/) in January 2002. Meeting that objective would have required completing CD-ROM masters for production well before XP was in the mainstream. Not long ago you would have been safe releasing a product that runs only on Windows 9x. In fact, you still find Win32 applications on the shelf that say they do not run under Windows NT, which is notorious for unconventional (as in, "incompatible with Win9x") implementation of the Win32 API. But, as of Christmas 2001, new computers from major manufacturers come with Windows XP by default. XP is a Windows 2000 derivative, which is an NT derivative, so be prepared to test your applications on all the operating systems.

To understand this particular problem, you must look at the code that the Wave and WavePlayer classes use when the client constructs a WavePlayer-derived object and calls the Play member function. (The wave.h, wave.cpp, waveplayer.h, and waveplayer.cpp files are available electronically; see "Resource Center," page 5.) The Wave constructor instantiates and initializes two WAVEHDR structures. The WavePlayer constructor prepares the structures for audio playback by calling the Win32 waveOutPrepareHeader function. The Play member function gets playback started by calling the FillBufferAndPlay member function once for each of the two structures. Using two structures supports overlapped waveform playback. The FillBufferAndPlay member function waits for the WHDR_DONE bit to be set in the header's dwFlags data member, and that was the problem. Under Windows 98/ME, the waveOutPrepareHeader function apparently leaves the dwFlags data member alone, and I had initialized it to WHDR_DONE so the test would not wait the first time. Under Windows XP (and, I guess, NT and 2000), the function clears that bit. The API documentation says you have to initialize the dwFlags data member to zero before calling waveOutPrepareHeader, but I thought I knew better and tried to get away with something. By waiting for the bit to be set in the first calls to FillBufferAndPlay, the program goes into a lifeless loop under XP. To fix it, I sheepishly added a special first-time state variable to the program to get past the test the first time in. Neither Tim's nor Charles's code depended on the WHDR_DONE bit the way mine did. I had privately congratulated myself for a more elegant solution that was able to play back audio waveform data with less code by twiddling that bit. Some guys never learn.

VC++ and the std Namespace

The second problem with my wave processing class library was simple enough: It has to do with the std namespace. I reported last month that the C++ compiler included with Visual Studio 6.0 does not put certain Standard C++ constructs into the std namespace by default. Specifically, the auto_ptr class and all the standard exception classes are in the global namespace. An internal compile-time directive remedies this error but is not defined by default. I recently installed a beta version of Visual Studio.NET 7.0, and this version of the C++ compiler uses the namespace convention by default. This is a good thing and a bit overdue; the standard has been in force for three and a half years. To compile my audio application with VC++ 7.0, I had to qualify references to auto_ptr and the exception classes with the std namespace qualifier.

There really is no excuse for leaving auto_ptr and the exception classes in the global namespace, except perhaps that they were conceived by the committee before namespace conventions were agreed upon. That's the price we pay when we allow a programming language standards committee to invent a language beyond the codification of existing practice. Earlier versions of Visual C++ also neglect to put Standard C library declarations in the std namespace when a program uses new-style headers, yet another violation of the Standard C++ specification. Example 1 is invalid Standard C++ code that is acceptable to Visual C++ 6.0 and earlier. I call it "interim" code because it's somewhere between legacy and standard. If the program used old-style headers, it would be legacy code. If the program qualified printf with std::, it would be standard code. Adhering to neither old conventions nor young standards, Example 1 looks more like code that's having a midlife crisis.

Example 2 is valid Standard C++ code, but VC++ 6.0 and earlier do not compile it, complaining that std is not a namespace. This issue generated a lot of criticism from C++ programmers who felt that Microsoft, whose fierce opposition to putting the C declarations into std was voted down in committee, were arrogantly flexing and flaunting their market share. Of course, we know the Redmond rugrats would never do that.

Visual Studio.NET 7.0 almost fixes this anomaly. It properly compiles Example 2. But, guess what? It also compiles Example 1. My only guess is that Microsoft wanted to protect its own legacy code from being broken, a legacy that would not exist if earlier compiler versions had been more compliant. I can only guess; I've learned not to ask. When journalists ask Microsoft technical questions, we get spin rather than answers.

This oddball dual personality of std raises a question. If a compiler properly compiles correct code but also compiles incorrect code, is it truly a compliant compiler? I've heard it argued that language and library extensions are okay as long as the compiler behaves properly when given correct code. But this particular extended behavior defeats the reason for having those symbols in std in the first place, or for putting anything in any namespace for that matter, which is to protect programmers from name collisions. Apparently symbols such as printf are in both the global and std namespaces under VC++ 7.0, and the protection is only an illusion.

An aside: I don't usually discuss beta versions of development tools because most often I get them with the understanding that I'll wait for a formal release before mentioning them publicly. In this case, Visual Studio.NET 7.0 Beta 2 was bundled on a DVD with a recent issue of DDJ, so I felt no obligation to keep quiet about it.

Seeing Sharp

Having Visual Studio.NET gives me a chance to play with Microsoft's C# programming language. I had a brief exposure to C# earlier in 2001 when I did a tech review of one of the new C# books that was about to be published. My first reaction to C# (other than that it's a direct name ripoff of the venerable old D-Flat) was that it's a nice language, but I wondered why we needed another nice language. We already have C++, a nice language available on most platforms. C# is available only on platforms that implement .NET, and as far as I know, there's only one, or, at least one platform family, name of Windows. I suppose C# is supposed to be Microsoft's answer to Java, which the company learned the hard way (in litigation) it could not control. But Java and C# seem aimed at different targets. Java is supposed to be a platform-independent solution — write once, run anywhere. Whether it ever achieves that objective remains to be seen. C# is not. But C# is one of three languages that run on top of Microsoft's .NET Common Runtime Language base, the other two being C++ and Visual Basic. Given C++, I'm not sure why we need C#, except perhaps to appease Java programmers by giving them an alternative to C++. Having already ascended the C++ learning curve, I don't need an alternative. But it's always fun looking at one.

CLR

The exciting thing about .NET is the Common Language Runtime (CLR) itself. The CLR offers the possibility for true multiple-language solutions to problems within which various parts of the problem are best solved with different languages, at the same time offering some layer of transparent interlanguage communication between solution components. Carried to its ultimate, the CLR would be implemented on all hardware and Internet platforms and would have sitting atop of it translators for all languages. Maybe even Java.

C#: A Better C++?

C# can be considered the next step in the evolution of languages that started with C. Presumably, C# fixes all the problems that C++ has because of C++'s enforced compatibility with C. We'll see. Some of the problems — the preprocessor, for example — are only in the eye of the beholder. Some of us pragmatists consider the preprocessor to be one of the strengths of C++ and would rue its loss. Same for multiple inheritance. If a class hierarchy is to truly model its problem domain rather than simply support the software solution, there are object networks that cannot be accurately represented without multiple inheritance. The fact that heap management, pointers, the preprocessor, multiple inheritance, and the like have their knurly knots does not render the tools unusable. One learns the limits and pitfalls associated with one's tools and proceeds with attendant caution. A chain saw improperly employed can remove many fingers, but it's still the most effective tool for felling a small-to-medium tree. With that gauntlet thrown down, I'll concede that C# looks like a good next-generation language, abandon the language wars for a later time, and concentrate on one of C#'s so-called improvements that looks really odd to me.

C#'s Main

What's with the way C# implements the Main function? In C and C++, every program needs one and only one function named main, which defines the entry point into the program, and which is a nonstatic, nonmember function in the global namespace. That device works well, but main spits in the face of object-oriented purity because it represents executable code that is not what is called a method in the object-oriented lexicon. C# addresses this perceived anomaly by emulating Java. You must declare a class that has a static function named Main. (In Java, it's main, no caps.) The odd part is that the class can be any class you define for any other purpose. It's just that the Main function has to be in some kind of a class. And since it does not execute in the name of any particular object of the class, Main must be static.

Oddly, you can code more than one class containing a Main function; when you do that silly thing, you have to tell the compiler which Main is mainly the main Main. Since the compiler has an option that lets you specify the Main function, why can't you call it anything you want? I might want to enter my program through Spongebob.Squarepants, for example.

It would make more sense to me from a purely aesthetic view if the language required you to declare an object of a class (or of a class derived from a class) with some specified name, such as Program or, in .NET parlance, Solution. Perhaps there should be a system-defined class named something like Solution with a virtual function named Main that had to be overridden in a program-specific derived class to provide the entry point and other initializing components for the program. That's how it ought to be. But that's what happens when they don't check with me first before designing a programming language.

Perhaps you can tell from this discussion exactly how far I've gotten with C#. Yep, see Example 3. At the same time, and to gain some insight into my ability to form cogent first impressions, return to the thrilling days of yesteryear via the DDJ CD-ROM to read what I had to say about C++ when I first tried it in 1989.

C++ For C# Programmers?

The C# books I've seen to date advise you to use the using statement to qualify references to things in the System namespace. Without it, the code in Example 3 would need to say System.Console.WriteLine. Following those guidelines, we would put a using namespace std; statement in Example 1, which would make it valid C++ for both the old VC++ compilers and the new one. But for several years, ever since the committee decided to put everything in the std namespace, we've been told it's bad form to take the easy way out with the using declaration, that it defeats the purpose of the std namespace. Now we're being told differently with new conventions for a new language. I'll have to get past Main to form an opinion.

DDJ


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.