Letters to the editor may be sent via email to [email protected], or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.
Dear CUJ,
I just got hold of your March 2002 issue and read John F. Hubbards article on binary code reuse (Binary Code Reuse in a Linux Environment). The use of Flex and Bison were given as an example to demonstrate a general point in solving a problem of launching Unix tools that work on stdin/stdout only. I agree with the general thrust of the argument, but found the article slightly misleading, particularly the assertion that if you left things as Flex and Bison have set them up, you would require your end users to type:
cat input_file.txt | BigCompiler"
By default, Flex will read from stdin, which seems like a reasonable default. However, it is a trivial task to make your Flex program read from an input file an example is even given on the man pages for my system, which (slightly reformatted) looks something like this:
#include <stdio.h> int main( int argc, char* argv[] ) { ++argv, --argc; /* skip over program name */ if ( argc > 0 ) yyin = fopen( argv[0], "r" ); else yyin = stdin; yylex(); return 0; }
The variable yyin is a FILE*. By simply assigning it to something other than stdin, you can read from an input file in about three lines of C code. I find this solution a lot less onerous than the one presented in the article for this particular class of problem.
Regards,
Paul Whitehead
Dear Paul,
Thanks for pointing out a simple, elegant solution to the problem of how to redirect Flexs input. Had I known about this technique, I might have chosen a different example for the article, if for no other reason than to avoid distracting readers who are Flex experts. As it was, I was simply delighted that I could run Flex and Bison effectively, without wasting most of my time!
Even with your technique available, however, I find that the compiler/compiler-driver architecture is a highly recommended approach for many problem domains. GCC uses it, as will many compiler creators, because it allows you to partition a complex problem along classic, easily understandable lines. That is to say, the driver program manages I/O and processes, while the other programs are specialized, encapsulated units of reuse.
Thanks,
John Hubbard
Hi CUJ,
Regarding Joey Rogers article Encapsulating Virtual Memory in Windows in CUJ (January 2002), there is a bug in Listing 1 on page 37.
m_hFile = ::CreateFile(filename, accessMode, shareMode, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(m_hFile == NULL) return 0;
This return value error checking is buggy. The MSDN documentation for CreateFile says:
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
The macro INVALID_HANDLE_VALUE is not NULL. For example, if the CreateFile tries to open a file that doesnt exist, the return value will be 0xffffffff, which is not NULL. The caller of CreateFile should check the return value against INVALID_HANDLE_VALUE.
Regards,
Unnikrishnan.C
Hi CUJ,
I am referring to Bill Gatliffs article Implementing Interrupt Service Routines in C++ in the February 2002 issue of CUJ.
In regards to the methods of handling the absence of the this pointer in ISR routines, I think the following snippet of code would illustrate Bills point clearer. Consider:
class device_c { public: device_c() // constructor initialize static "this" // counterpart { me = this; }; // non-static Interrupt Service Routine void isr(); // this-like static member static device_c *me; // static interrupt dispatcher, should be // inlined for efficiency static interrupt void isr_raw() { me->isr(); } // example of non-static data member int count; }; // your interrupt vector table has addresses of // raw handlers void (*vector_table[])() = { &device_c::isr_raw, // more raw ISRs }; // storage for static "this"-like member device_c *device_c::me = NULL; void device_c::isr() { // yes, we can do this, we have "this" // pointer!!! count++; }
By using this method, you do not need to use the me pointer in your real ISRs and can simply reference your non-static class members in a non-static member ISR function.
Of course, you should not create more than one instance of the device_c class without imposing a rule that the isr routine must only access static members. Therefore, this schema is useful for Singletons, and the only thing it really achieves is it avoids declaring of class members used in the isr function as static (fairly valid reason, I think).
Cheers
Michael Melkonian
Andrew and Barbara,
I have a minor nit-pick on an otherwise excellent article (C++ Made Easier: Naming Unknown Types, CUJ, February 2002). The typeof operator is more generally applicable than the article implies. In particular, it is not true that, with typeof, if f is a function, and we know that f takes a single argument, there is no way to write an expression that represents the type of that argument. The way out, as usual, is the canonical extra level of indirection, as shown in the attached code (which works with gcc 2.95.2).
The trick is to invoke the helper function std::ptr_fun inside a typeof expression and use the typedefs defined by the resulting function adapter:
typedef typeof( std::ptr_fun( f ) ) fpo_t; typedef fpo_t::argument_type argtype; typedef fpo_t::result_type restype;
For example, if f is declared as:
double f( int );
then those typedefs are equivalent to:
typedef std::pointer_to_unary_function <int,double> fpo_t; typedef int argtype; typedef double restype;
The key observations are:
- The helper function std::ptr_fun is never called.
- The function adapter object is never created.
- The programmer never needs to write out the explicit type of the function adapter.
- The scope of the definitions of argtype and restype are not restricted to a single function.
This trick works with std::ptr_fun for functions with one or two arguments and can be extended easily to functions with more arguments, class member functions, and doubtless other tricky cases or at least it would if typeof were standard.
Robert P. Goddard
You are quite right that if we can obtain a name that corresponds to the type of a function something that typeof could do for us we can then use a technique such as the one you suggest to obtain the type of the functions argument. Indeed, this particular technique is widely used in the standard library, std::ptr_fun being just one place where it is used.
But the fact that the technique is already used in the standard library shows that typeof is not necessary in order to solve that particular problem. In fact, I dont see how typeof would make the solution any easier. All that typeof would do is to give us a way of going from the name of a function to its type; the problem of extracting the argument type from the function type is still solved in the same way, with or without typeof.
For example, suppose we were to make a tiny change to the C++ language definition to allow an expression of the form e.m to denote either a value or a type, depending on whether member m of the class that is the type of e denotes a value or a type. Suppose further that if e.m denotes a type, then the expression e is not evaluated. (It doesnt need to be evaluated, because all we need is its type.) Then we wouldnt need typeof to solve the function-argument problem, because we could write something like this:
// This class is already in the standard // library template <class Arg, class Res> struct unary_function { typedef Arg argument_type; typedef Res result_type; }; // This function is new template <class Arg, class Res> unary_function<Arg, Res> reveal(Res (*f)(Arg)) { return unary_function<Arg, Res>(); };
Then with our tiny language change, reveal(f).argument_type would be the type of fs argument, and reveal(f).result_type would be the type of fs result.
In this example, as in yours, what really extracts the argument type from the function type is not the use of typeof, nor it is the use of our hypothetical language feature. Rather it is a mechanism that already exists in C++, namely the ability to compute several template parameters from a single template-function argument that happens to incorporate several types. So in that sense, its not really typeof thats solving the problem.
I imagine that this discussion sounds like splitting hairs. Indeed, it probably is. The reason for splitting them is to try to clarify the sense in which we were claiming that typeof doesnt solve the original problem.
Regards,
Andrew Koenig