Stories
Slash Boxes
Comments

News for nerds, stuff that matters

Slashdot Log In

Log In

Create Account  |  Retrieve Password

Don't Overlook Efficient C/C++ Cmd Line Processing

Posted by CmdrTaco on Sun Jul 29, 2007 10:33 AM
from the also-don't-eat-yellow-snow dept.
An anonymous reader writes "Command-line processing is historically one of the most ignored areas in software development. Just about any relatively complicated software has dozens of available command-line options. The GNU tool gperf is a "perfect" hash function that, for a given set of user-provided strings, generates C/C++ code for a hash table, a hash function, and a lookup function. This article provides a reference for a good discussion on how to use gperf for effective command-line processing in your C/C++ code."
+ -
story
This discussion has been archived. No new comments can be posted.
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More
Loading... please wait.
  • by tot (30740) on Sunday July 29 2007, @10:40AM (#20032263)
    I would not consider speed of command line option processing to be bottleneck in any application, the overhead of starting of the program is far greater.
    • by ScrewMaster (602015) on Sunday July 29 2007, @10:42AM (#20032279)
      I'd say the speed of human motor activity is an even greater limiting factor.
      • Re: (Score:3, Informative)

        What a limited point of view. See "man system", for example.

        -Peter
      • Re: (Score:3, Insightful)

        I'd say the speed of human motor activity is an even greater limiting factor.


        I wouldn't bet on that. The command line is not just a human/computer interface, but also a computer/computer interface. It's very common for one script to fire off many others.


        That said, I agree with the grandparent that it's hard to imagine a program where command line processing is a significant runtime expense.

    • by ChronosWS (706209) on Sunday July 29 2007, @10:46AM (#20032301)
      Indeed, what the hell? Now you have to have another tool and another source file for what is essentially declaring a dictionary in C++, which should be in any good developer's library? Yeesh.

      If you don't like the nasty nested ifs, make the keys in your dictionary the command line options and the values delegates, then just loop through your list of options passed on the command-line, invoking the delegate as appropriate. Eliminates the if, there are no switch statements either, and each of your command line arguments is now handled by a function dedicated to it, bringing all of the benefits of compartmentalizing your code rather than stringing it out in a huge processing function.
      • Now you have to have another tool and another source file for what is essentially declaring a dictionary in C++, which should be in any good developer's library?
        Due to the brokenness of how some linkers handle virtual method lookup tables, using anything from the C++ standard library tends to bring in a large chunk of dead code [wikipedia.org] from the standard library. I compiled hello-iostream.cpp using MinGW and the executable was over 200 KiB after running strip, compared to the 6 KiB executable produced from hello-cstdio.cpp. Sometimes NIH syndrome produces runtime efficiency, and on a handheld system, efficiency can mean the difference between fitting your app into widely deployed hardware and having to build custom, much more expensive hardware.
        • by sentientbrendan (316150) on Sunday July 29 2007, @01:36PM (#20033479)
          It sounds like the author is statically linking his library and running on embedded an embedded system. It is not surprising in that case that the c++ standard library brings in much more code than the c standard library, but it should be made clear that it is not relevant to desktop developers, pretty much all of which dynamically link with glibc.

          Again, to be clear, dynamically linking with the c++ standard library is not going to increase your executable size. Please don't try to roll your own code that exists in the standard library. It is a real nuisance when people do that.

          I should qualify that by saying that template instantiations do (of course) increase executable size, but that they do so no more than if you had rolled your own.
          • It is not surprising in that case that the c++ standard library brings in much more code than the c standard library, but it should be made clear that it is not relevant to desktop developers, pretty much all of which dynamically link with glibc.

            On MinGW, the port of GCC to Windows OS, my programs dynamically link with msvcrt, not glibc. Also on MinGW, libstdc++ is static, just like in the embedded toolchain. Are you implying that one of the C++ toolchains for Windows uses a dynamic libstdc++? Which toolchain for which operating system that is widely deployed on home desktop computers are you talking about?

          • HOLY SHIT! 194KB BIGGER?! HOW WILL YOU EVER FIND THE SPACE FOR SUCH A HUGE EXECUTABLE?!?!
            I develop for a battery-powered computer with 384 KiB of RAM. In such an environment, what you appear to sarcastically call a "mere couple hundred kilobytes" is a bigger deal than it is on a personal computer manufactured in 2007.
              • devkitARM (Score:3, Informative)

                And you do so using MinGW and c++?
                Yes, I do so with devkitARM [devkitpro.org] (a cross-compiling GCC toolchain that is itself compiled with MinGW) and C++.
                    • It's not pushing it all. It's storage, it's network attached, it's in a box... What I am pushing is the poor little linksys device. It's plugged into 4 USB hard drives (plus a thumb drive, but that's just for booting) which it's running software RAID5 on. Poor little thing, if it could scream I'm sure it would be. Sadly it's the only machine with a C++ compiler on it at home these days...

                      Please don't tell the poor thing it's running on MIPS, the ARMv5TE kernel might just freak out and collapse the universe.

              • How many of these embedded tools you write actually _do_ command line processing?

                None yet, but they do handle other things that involve dictionaries, such as character encoding conversion. A program designed to move items back and forth between a town in Animal Crossing (for Nintendo GameCube) and a town in Animal Crossing: Wild World (for Nintendo DS) needs to be able to understand the encodings of character names and town names that these games use, possibly by converting between their proprietary 8-bit codecs and UTF-8.

                why don't you invest in more (both memory- and time-) efficient ways to do IPC than the command line?

                Because the command line, pipes, and sockets are the most obvio

    • by Anonymous Coward on Sunday July 29 2007, @11:11AM (#20032473)
      You're not a real programmer if you won't over optimize unrelevant parts of your code.
    • by canuck57 (662392) on Sunday July 29 2007, @11:11AM (#20032479)

      I would not consider speed of command line option processing to be bottleneck in any application, the overhead of starting of the program is far greater.

      Your just experiencing this with Java, Perl or some other high overhead bloated program. People often pull out a heavy weight needing a 90MB VM or a 5-10MB basis library calling the cats breakfast of shared libraries I would agree, but lets take a look at C based awk for example, it is only a 80kb draw. Runs fast, nice and general purpose and does a good job of what it was designed to do. It can be pipelined in, out and used directly on the command line as it has proper support for stdin, sndout and stderr. On my system, only 10 disk blocks to load.

      While fewer people are proficient at it, C/C++ will outlast us all for a language. Virtually every commodity computer today uses it in it's core. Many others have come and gone yet all our OSes and scripting tools rely on it. So any dooms day predictions would be premature, and if your want fast, efficient and lean code you do C/C++....

      • Re: (Score:3, Insightful)

        While fewer people are proficient at it, C/C++ will outlast us all for a language. Virtually every commodity computer today uses it in it's core.

        Which is why they are so crash-prone. With C/C++, any mistake whatsoever will likely crash the program/machine, and possibly also allow crackers to make the program execute arbitrary code.

        Many others have come and gone yet all our OSes and scripting tools rely on it. So any dooms day predictions would be premature, and if your want fast, efficient and lean co

    • by ai3 (916858) on Sunday July 29 2007, @12:11PM (#20032857)
      You must not have seen the recent proposal for GNU tools options, which will require four dashes instead of two and a minimum of four words per option. Under a UN/EU funded program to ease the transition to intelligent machines, developers are rewarded for implementing full-sentence options and/or prose. But initial experiments showed that many users where unwilling to wait for the parsing of the command "remove-files --recursively-from-root-directory --do-not-ask-for-confirmation-just-delete --i-really-want-this!" just to be 1337, which led to whatever development efforts are mentioned in the article, which I didn't read.
        • What is the problem with tabs? Are there any text editors/compilers that anyone uses that don't support tabs? I find them to be better than multiple spaces, even if the text editor has tab mapped to multiple spaces.
          • Re: (Score:3, Interesting)

            What is the problem with tabs?

            The problem is that people set their tab breaks at all sorts of places (eg: every 4 characters), and then use tabs to space things in the middle of lines, or they'll mix tabs and spaces at the beginnings of lines. When somebody with different settings opens the same file, the indentation looks really screwed. That happens even after you've gotten everybody to agree on a common number of columns for indentation.

            I only know of two solutions:

            1. Make all software, everywhere,
          • Re: (Score:3, Insightful)

            "Mixing tabs and spaces for indenting is bad. It causes many problems that you don't encounter when using only spaces. Therefore, tabs are bad, so only use spaces."

            That is the only significant argument against tabs I've ever read, and I've probably read it a hundred times. Only a moron wouldn't realize that it's the mixing that is bad, not the tabs or the spaces, but apparently there are a lot of morons out there.

            tabs: good
            spaces: good
            mixing tabs and spaces: bad

            I personally prefer tabs. Why?
            • Different code
  • Too much (Score:4, Insightful)

    by bytesex (112972) on Sunday July 29 2007, @10:41AM (#20032269) Homepage
    I'm not sure that for the usually simple task of command line processing, I'd like to learn a whole new lex/yacc syntax thingy.
    • Re:Too much (Score:5, Insightful)

      by hackstraw (262471) on Sunday July 29 2007, @06:26PM (#20036061) Homepage
      I'm not sure that for the usually simple task of command line processing, I'd like to learn a whole new lex/yacc syntax thingy.

      The syntax for gperf is not that bad, but its simply the wrong tool for the job as far as commandline processing goes.

      gperf simply makes a "perfect" has function for searching a predetermined static lookup. It provides no mechanism for arbitrary arguments like input filenames or modifiers (like a filter for including/excluding things, or increasing/decreasing something) nor does it check for conflicting options or missing options.

      gperf would give you nothing besides a match of input to a state. gperf would provide nothing for a common commandline like: --include="*.txt" --exclude="*.backup" --with-match="some text|or this text" --limit-input=5megabytes

      getopt or just rolling your own if/else if ladder or switch statement would provide much more flexibility over gperf.

      Now, with parsing a configuration file, gperf might help, but for processing commandline arguments, gperf is simply the wrong tool for the job.

      This is like the second or third slashdot posting from IBM's developer works that is simply a well formated nonsense. Past examples are http://developers.slashdot.org/article.pl?sid=07/0 4/09/1539255 [slashdot.org] and http://developers.slashdot.org/article.pl?sid=07/0 4/09/1539255 [slashdot.org]

      This is silly on both slashdot and IBMs part.

  • by V. Mole (9567) on Sunday July 29 2007, @10:50AM (#20032331) Homepage
    Does the phrase "reinvent the wheel" strike a chord with anyone?
    • Yeah, because getopt(3) is a real bottleneck
      getopt() is in the header <unistd.h>, which is in POSIX, not ANSI. POSIX facilities are not guaranteed to be present on W*nd?ws systems. It also handles only short options, not long options. For those, you have to use getopt_long() of <getopt.h>, which isn't even in POSIX.

      Does the phrase "reinvent the wheel" strike a chord with anyone?
      If the wheel isn't licensed appropriately, copyright law requires you to reinvent it. Specifically, using software under the GNU Lesser General Public License [gnu.org] in a proprietary program intended to run on a platform whose executables are ordinarily statically linked, such as a handheld or otherwise embedded system, is cumbersome.
      • Re: (Score:3, Interesting)

        Are you seriously trying to argue that gperf is more portable than getopt?

          • Re: (Score:3, Informative)

            Absolutely. There is no platform for which gperf is a better, more portable option for command line processing than getopt. I'm not sure what you think getopt does that is "tricky" under Win32. Its a string processor.
              • Re: (Score:3, Informative)

                Again, on the off chance that this helps anyone reading this pitifully long and silly thread: it is trivial to make getopt work on Win32, just like it was trivial to make strsep work on Linux when it only had strtok. I object to the argument that "portability" has anything whatsoever to do with whether you'd use getopt to parse arguments.

                Like most of the other comments on this post, I find the idea of using gperf for "high performance argument parsing" superfluous and convoluted. In fact, I find the idea o

      • When faced with this issue, I simply wrote a Windows version of getopt. Took about a day.

        Even when reinventing the wheel, it is important to reinvent as little as possible. If you need functionality that isn't there, at least keep the same interface.
  • by Anonymous Coward on Sunday July 29 2007, @11:02AM (#20032399)
    Good grief. What a strawman of an example.
    Anyone writing or maintaining command line programs knows that they
    should be using the API getopt() or getopt_long().
    There are standards on how command line options and arguments are to be
    processed. They should be followed for portability and code maintenance.
    • There's a time and place for gperf - command line argumnet processing is not it!

      Actually, I've never really come across a case where I knew ahead of time the whole universe of strings I would be accepting, and so never ended up using it - gperf is a great idea, but this seems to be a case of someone really looking hard to figure out where they could shoehorn gperf into just for the sake of using it.
  • by geophile (16995) <jao.geophile@com> on Sunday July 29 2007, @12:05PM (#20032819) Homepage
    Perfect hash functions are curiosities. If you have a static set of keys, then with enough work you can generate a perfect (i.e. collision-free) hash function. This has been known for many years. The applicability is highly limited, because you don't usually have a static set of keys, and because the cost of generating the perfect hash is usually not worth it.

    Gperf might be reasonable as a perfect hash generator for those incredibly rare situations when the extra work due to a hash collision is really the one thing standing between you and acceptable performance of your application.

    I thought maybe we were seeing a bad writeup, but no, it's the authors' themselves who talk about the need for high-performance command-line processing, and give the performance of processing N arguments as O(N)*[N*O(1)]. I cannot conceive of a situation in which command-line processing is a bottleneck. And their use of O() notation is wrong (they are claiming O(N**2) -- which they really don't want to do, not least because it's wrong). O() notation shows how performance grows with input size. Unless they are worrying about thousands or millions of command-line arguments, O() notation in this context is just ludicrous.

    I don't know why I'm going on at such length -- the extreme dumbness of this article just set me off.
          • Re: (Score:3, Interesting)

            I challenge: cite as an example any fixed set of strings (such as would be applicable for perfect hashing) for which a realistic perfect hashing scheme of any sort outperforms a statically-sized conventional chaining table using a trivial 33/37-style [google.com] string hash. I don't think you can. Gperf languishes in obscurity for a reason.

  • Historically? (Score:4, Insightful)

    by ClosedSource (238333) on Sunday July 29 2007, @12:07PM (#20032839)
    "Command-line processing is historically one of the most ignored areas in software development."

    This is like saying that walking is historically one of the most ignored areas in human transportation.
  • is this a joke? (Score:3, Insightful)

    by oohshiny (998054) on Sunday July 29 2007, @12:14PM (#20032879)
    If it's not, the author of that article should be kept as far away from writing software as possible; he epitomizes the attitude that so frequently gets C++ programmers into trouble.
    • Re: (Score:3, Insightful)

      Well, what do you expect from IBM? It's just another one of their look-Ethel-it's-open-source-and-look-at-us-helping -the-community content-free PR fluff pieces. Ignore them and they'll crawl back into their mainframe cave.

  • by pclminion (145572) on Sunday July 29 2007, @12:21PM (#20032927)
    Where's the Foot icon? Optimizing command line parsing? Oh God, my sides are splitting.
    • Re: (Score:3, Insightful)

      The weird bit is that, despite being a somewhat silly article, it launched one of the most intelligent discussions I've seen on /. in a while.
  • Something Eric Allman wrote many moons ago. I found it and modified it to support "native" command line syntax on MS-DOS, VMS, and AmigaDOS, and added some support for improved self-documentation... and then Brad Appleton saw it and rapidly enhanced it to support a plethora of shells and interfaces until it took up 10 posts in comp.sources.misc.

    The following two directories should bring it up to the latest version I know of.

    This is not efficient, mind you. Command line parsing doesn't generally need to be efficient, even by my miserly standards, honed when a PDP-11 was something you hoped to upgrade to... some day...

    ftp://ftp.uu.net/usenet/comp.sources.misc/volume29 /parseargs/ [uu.net]
    ftp://ftp.uu.net/usenet/comp.sources.misc/volume30 /parseargs/ [uu.net]

    PARSEARGS
     
                            extracted from Eric Allman's
     
                                NIFTY UTILITY LIBRARY
     
                              Created by Eric P. Allman
                                <eric@Berkeley.EDU>
     
                            Modified by Peter da Silva
                                <peter@Ferranti.COM>
     
                      Modified and Rewritten by Brad Appleton
                              <brad@SSD.CSD.Harris.COM>
    Brad's latest work in this area seems to be here:

    http://www.cmcrossroads.com/bradapp/ftp/src/libs/C ++/CmdLine.html [cmcrossroads.com]

    http://www.cmcrossroads.com/bradapp/ftp/src/libs/C ++/Options.html [cmcrossroads.com]

  • by stupendou (466135) on Sunday July 29 2007, @03:35PM (#20034467)
    Try supergetopt instead. Much easier to use and also open source.
    http://www.ibiblio.org/pub/Linux/devel/sugerget-1. 1.tgz [ibiblio.org]

    With this code, you simply specify command-line strings and variables in a printf()
    style format.

    E.g. supergetopt( argc, argv,
                                        "string1", "%d %d", function1,
                                        "string2", "%s", function2 )

    will call function1( int a, int b ) when string1 is on the command line,
    and will call function2( char *s ) when string2 is used on the command line.

    A whole lot easier than gperf, IMHO.
    • Re:C++ I get (Score:4, Insightful)

      by Anonymous Coward on Sunday July 29 2007, @11:01AM (#20032393)
      I do. On MIPS, ARM, PPC, x86, and all the other embedded stuff. I don't think C will ever die - it's the universal assembler language.
    • by V. Mole (9567) on Sunday July 29 2007, @11:04AM (#20032419) Homepage
      There's this little project of which you may have heard: http://www.kernel.org/ [kernel.org]
    • Re: (Score:3, Insightful)

      I use C for any low-level programming project that doesn't warrent an object-oriented approach.

      The trick is to identify the best tool for the job.
      • Re:C++ I get (Score:5, Interesting)

        by mce (509) on Sunday July 29 2007, @11:25AM (#20032567) Homepage Journal

        You, whenever you compile C++ code, as it is compiled to C before machine code (unless you are using an exotic compiler such as the Compaq AXP C++ compiler for TRU64).

        Excuse me???? That was not even true anymore when I started using C++, back in 1992. There are features in the C++ standard that are so extremely difficult to correctly implement in standard compliant C that it's a complete waste of effort trying to pass via C while compiling. Exception handling comes to mind as the prime example. A failed attempt to support exceptions was the reason why Cfront 4.0 was abandoned. Note that 3.0 was released as early as 1991. The last Cfront based compiler I had the horor of using was HP's CC. It was superseeded by the new native aCC by 1994 at the latest.

        By the way, I used to write C/C++ compilation/optimisation stuff for a living, so I guess I know something about the topic.... :-)

          • Re:C++ I get (Score:4, Informative)

            by mce (509) on Sunday July 29 2007, @02:24PM (#20033809) Homepage Journal

            Of course C++ exceptions are what I meant. What else would I mean when using the word "exceptions" in this context?

            And yes, C++ exceptions can be expressed in C. After all, C is a glorified assembler and the resulting code from C++ translation is assembler as well. It all depends in the level of abstraction at which write the C code is written and on the amount of uglyness/inefficiency you're willing to take on board (and also the trade-off between both of the latter). But that's not the point. The point of this thread is that nowadays it makes no sense to make use of this capability in a C++ compiler. Especially not when considering that a user of a C++ compiler wants more than just a compiler. He also wants a debugger that is able to meaningfully link up the binary and the original C++ source. If you're a C++ compiler vendor, using C as an IL does nothing but complicate your own life. Twice.
            • Re:C++ I get (Score:4, Informative)

              by mce (509) on Sunday July 29 2007, @04:58PM (#20035175) Homepage Journal

              The main problem (but not the only one) is called "object destructors". You have to make sure they are called. All of them, and in the correct order, at all the nested scopes of execution you are in when the exception occurs. And you need to make sure not to call them on any object not yet constructed (always remember that constructors can throw exceptions too) and never to call a destructor twice (I've seen this kind of bug multiple times in multiple compilers). And then there is the fun of exceptions thrown by destructors, not to mention the possibility that it all happens in the middle of constructing or destructing an array of objects.

              All that is why setjmp()/longjmp(), also known as C's non-local goto, don't cut it, which in turn means that you need to complicate function return mechanisms. And just when you think you got that problem sorted out, you need to be aware that C++ functions can call (library) C functions that were never compiled to even know about exceptions but that in turn can call C++ functions that may again throw an exception. The entire construction needs to be able to handle this.

              As I wrote in an other post [slashdot.org] in this thread, it can be done. But it is not easy. Note that the entire object destructor issue also applies within a single scope, which is why life is not as easy as replacing every "throw" statement by "goto end;".

      • Re:C++ I get (Score:5, Informative)

        by Enselic (933809) on Sunday July 29 2007, @11:33AM (#20032619) Homepage

        You are wrong about 3):

        The process of building the new engine went much more smoothly than anything we have done before, because I was able to do all the groundwork while the rest of the company worked on TeamArena. By the time they were ready to work on it, things were basically functional. I did most of the early development work with a gutted version of Quake 3, which let me write a brand new renderer without having to rewrite file access code, console code, and all the other subsystems that make up a game. After the renderer was functional and the other programmers came off of TA and Wolf, the rest of the codebase got rewritten. Especially after our move to C++, there is very little code remaining from the Q3 codebase at this point.

        Source: http://archive.gamespy.com/e32002/pc/carmack/ [gamespy.com]


        And 4) as well:

        Historically, compilers for many languages, including C++ and Fortran, have been implemented as "preprocessors" which emit another high level language such as C. None of the compilers included in GCC are implemented this way; they all generate machine code directly. This sort of preprocessor should not be confused with the C preprocessor, which is an integral feature of the C, C++, Objective-C and Objective-C++ languages.

        Source: http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/G_002b _002b-and-GCC.html [gnu.org]

    • Re:Joke? (Score:5, Insightful)

      by iangoldby (552781) on Sunday July 29 2007, @11:20AM (#20032539) Homepage

      Someone found a "new" toy?
      Well I for one won't be using this to process command-line arguments (that's what getopt() and getopt_long() are for), but it is certainly useful to know of a tool that I can use to generate a perfect hash. The next time I need some simple but efficient code to quickly discriminate between a fixed set of strings, I'll know to Google for gperf. (Before I read this article I didn't even know it existed.)