• anne (unregistered)

    hey, I like the idea of the static analysis, but WTF (why TF) use a proprietary tool that not all of us can get our hands on without spending $$? Why not just use lint???

    I see Coverity has a free trial, but I really would rather not whore my info to them and be on their awful mailing list forever more.

  • anne (unregistered) in reply to anne
    anne:
    hey, I like the idea of the static analysis, but WTF (*why* TF) use a proprietary tool that not all of us can get our hands on without spending $$? Why not just use lint???

    I see Coverity has a free trial, but I really would rather not whore my info to them and be on their awful mailing list forever more.

    As soon as I submitted that, my question was answered by the banner ad for Coverity at the top of the page. I'm sad.

  • Foobar (unregistered) in reply to EvanED
    EvanED:
    Foobar:

    My point of view is that variables should only be declared at the beginning of a scope and before any statements. This IMO makes it much easier to read through code you don't know. Uncertain of what type something is? Well, just scroll up to the beginning of the scope and you will find the declaration. Also if you use more than one loop, declaring i multiple times is just silly.

    I do realise that C99 considers "for(" the beginning of a new scope, but I completely disagree with C99 here. C99 allows declaration of variables anywhere anyway, which I also completely diagree with. It's just promoting sloppy programming.

    See, I think personal preference. I think it's easier to find things if they are near their uses. If the function is short, it doesn't make much difference; if the function is long, it means that you have less chance of scrolling and also that the block of declarations is likely pretty sizable.

    But "near their use" is a variable not easy to determine. At the beginning of the scope is MUCH easier to find.

    {
       [ ... 50 lines of code ... ]
    
       char *foo;
    
       foo = bar();
    
       [... 50 more lines follow ...]
    
       blah(foo);
    

    If you're looking at the last line, how easy is it to find the definition of foo? Well, it's not easy at all.

    EvanED:
    In either case, if you're using an IDE then there's no issue figuring out where the declaration is, as there's a "go to declaration" action. Heck, Visual Studio will show you the type of the variable the mouse is over in a tool tip.

    But there's no reason to make the code harder to read and require some IDE, require the reader to move the mouse over every variable to find its type, etc. That's just making things harder for no reason at all.

    EvanED:
    In addition, "declare anywhere" also often/usually allows you to initialize the variable at the point of declaration,

    Which is a thing I consider evil. It increases clutter A LOT. How often haven't I seen a C++ program with one huge block of mixed declarations and statements? Pretty often. And it's pretty hard to read that way.

    EvanED:
    something you can rarely do in C, which reduces the chance of using an uninitialized or improperly initialized variable.

    No, any remotely decent compiler will tell you when you use a variable uninitialised. Forcing people to clutter their code and make it unreadable to "reduce the chance of using an uninitialised variable" really is a non-argument.

  • Turambar (unregistered) in reply to Foobar
    Foobar:
    Another thing I see scaringly often by C++-programmers-turned-C is something like:
    x = new char[strlen(y)];
    strcpy(x, y);
    

    And then after a while, someone taps me on the shoulder, asks me if I know why the new operator would be crashing and if it is a bug in the operating system. Of course the new that's crashing is the one after the code I wrote.

    I'm a "C/C++ programmer who actually doesn't know C", could you enlighten me on why that code doesn't work?
  • EvanED (cs) in reply to anne
    anne:
    hey, I like the idea of the static analysis, but WTF (*why* TF) use a proprietary tool that not all of us can get our hands on without spending $$? Why not just use lint???

    I see Coverity has a free trial, but I really would rather not whore my info to them and be on their awful mailing list forever more.

    Um, maybe because too Lint isn't at all the same thing?

    They both look for potential bugs, but that's about as far as their similarity goes.

  • EvanED (cs) in reply to Turambar
    Turambar:
    Foobar:
    Another thing I see scaringly often by C++-programmers-turned-C is something like:
    x = new char[strlen(y)];
    strcpy(x, y);
    

    And then after a while, someone taps me on the shoulder, asks me if I know why the new operator would be crashing and if it is a bug in the operating system. Of course the new that's crashing is the one after the code I wrote.

    I'm a "C/C++ programmer who actually doesn't know C", could you enlighten me on why that code doesn't work?

    strlen returns the number of characters in the string not including the terminating null, so there isn't enough space allocated by new for strcpy to append the null.

    Boom, instant buffer overrun.

  • JamesCurran (cs) in reply to Foobar
    Foobar:
    Right, it actually does compile. The code that had the problem looked like this:
    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    Now I don't know if that's a compiler bug or really intended in C++

    No that was intended... Or to be more exactly, it doesn't fall under the hack which allowed the first sample. A text literal is a const char[], which can be implictly, converted to a const char* or (if necessary) a char*. Note that the last conversion only applies to a text literal. So, the expression (blah?"foo":"bar") as a whole is a const char*. (actually, since both literals are the same size not conversion at all is needed, so it might even consider it a "const char[3]". Regardless, the expression as a whole is not a text literal, and therefore cannot be converted to a "char*".

    No, I'm saying that C is a different language from C++ because while they're syntactically similar (though not identical), the way the two languages are used, especially when it comes to allocation, error handling and standard libraries, means that C knowledge can't just be transferred into C++ knowledge and C++ knowledge can't just be transferred into C knowledge. You need to learn both languages, and thus they're distinct.

    For the most part, I agree, but one must consider degrees of distinction. There is about a 80-90% overlap in "C Knowledge" and "C++ Knowledge". And much of the 10-20% difference is C++ not allowing the kind of idiomatic/sloppy programming that C only allows because the first C compilers had to run in 32K and were more concerned with code generation than syntax checking.

    Well, I can extend that. Any well written C++ program will be compilable with a C compiler.

    When your definition of a well written C program is something that compiles with a C++ compiler, well, then the argument is lost before it even started.

    Oh well, you suddenly went from competent debater to idiot/jackass. No, my definition of a well-written C program has nothing to do with C++ compiler. Apparently, you don't really understand the concept of "well-written". Let's take for example, the code you posted before:

    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    The fact that this passes through a C compiler does NOT mean it is "well-written". Properly, it should be:

    extern int blah;
    void foo(const char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    "const" has been part of the C language for 18+ years, so it's about time you actually learned this language you defend so much. In fact, "const" was added to the language at the same time the parameters were added to function declarations (Previously, that would have had to be written as "void foo();") So you can't even fall-back on claiming that it's legacy K&R C code --- The sample was written wrong to start with.

    C++ has a lot of "features" over C which makes code much harder to read, much harder to maintain and overall puts the code in a lot worse condition. Though I don't expect you to agree.

    No Comment --- I'll just let the readers judge with is "harder to read, much harder to maintain and overall puts the code in a lot worse condition"

    C++:

    main()
    {
    std::string A = "Hello";
    std::string B = "world";
    std::string C = A +", " + B + "!";
    cout << C << endl;
    }

    C:

    main()
    {
    const char A[] = "Hello";
    const char B[] = "world";
    char * C = malloc(strlen(A) + strlen(B) + 4);
    // That's +2 for comma-space, +1 for bang, and +1 for NUL
    if (C == NULL)
    exit();
    strcpy(C,A);
    strcat(C, ", ");
    strcat(C,B);
    strcat(C, "!");
    printf("%s\n", C);
    free(C);
    }

    Addendum (2007-04-25 13:45):

    Foobar:
    Right, it actually does compile. The code that had the problem looked like this:
    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    Now I don't know if that's a compiler bug or really intended in C++

    No that was intended... Or to be more exactly, it doesn't fall under the hack which allowed the first sample. A text literal is a const char[], which can be implictly, converted to a const char* or (if necessary) a char*. Note that the last conversion only applies to a text literal. So, the expression (blah?"foo":"bar") as a whole is a const char*. (actually, since both literals are the same size not conversion at all is needed, so it might even consider it a "const char[3]". Regardless, the expression as a whole is not a text literal, and therefore cannot be converted to a "char*".

    No, I'm saying that C is a different language from C++ because while they're syntactically similar (though not identical), the way the two languages are used, especially when it comes to allocation, error handling and standard libraries, means that C knowledge can't just be transferred into C++ knowledge and C++ knowledge can't just be transferred into C knowledge. You need to learn both languages, and thus they're distinct.

    For the most part, I agree, but one must consider degrees of distinction. There is about a 80-90% overlap in "C Knowledge" and "C++ Knowledge". And much of the 10-20% difference is C++ not allowing the kind of idiomatic/sloppy programming that C only allows because the first C compilers had to run in 32K and were more concerned with code generation than syntax checking.

    Well, I can extend that. Any well written C++ program will be compilable with a C compiler.

    When your definition of a well written C program is something that compiles with a C++ compiler, well, then the argument is lost before it even started.

    Oh well, you suddenly went from competent debater to idiot/jackass. No, my definition of a well-written C program has nothing to do with C++ compilers. Apparently, you don't really understand the concept of "well-written". Let's take for example, the code you posted before:

    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    [/code]

    The fact that this passes through a C compiler does NOT mean it is "well-written". Properly, it should be:

    extern int blah;
    void foo(const char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    [/code]

    "const" has been part of the C language for 18+ years, so it's about time you actually learned this language you defend so much. In fact, "const" was added to the language at the same time the parameters were added to function declarations (Previously, that would have had to be written as "void foo();") So you can't even fall-back on claiming that it's legacy K&R C code --- The sample was written wrong to start with.

    C++ has a lot of "features" over C which makes code much harder to read, much harder to maintain and overall puts the code in a lot worse condition. Though I don't expect you to agree.

    No Comment --- I'll just let the readers judge with is "harder to read, much harder to maintain and overall puts the code in a lot worse condition"

    C++:

    main()
    {
    std::string A = "Hello";
    std::string B = "world";
    std::string C = A +", " + B + "!";
    cout << C << endl;
    }

    C:

    main()
    {
    const char A[] = "Hello";
    const char B[] = "world";
    char * C = malloc(strlen(A) + strlen(B) + 4);
    // That's +2 for comma-space, +1 for bang, and +1 for NUL
    if (C == NULL)
    exit();
    strcpy(C,A);
    strcat(C, ", ");
    strcat(C,B);
    strcat(C, "!");
    printf("%s\n", C);
    free(C);
    }

  • EvanED (cs) in reply to Foobar
    Foobar:
    No, any remotely decent compiler will tell you when you use a variable uninitialised.
    #include <stdio.h> 
    
    int main() {
      int* x;
      printf("%d", *x);
    }

    This code compiles without warnings on GCC 3.4 and 4.1 (gcc -W -Wall and g++ -W -Wall). I would consider both of them to be "remotely decent".

    As for the rest, I guess again we disagree. I don't find myself needing to know the type of a variable and not being able find the declaration at all frequently, and think the readibility and other benefits outweigh those times.

  • AC (unregistered) in reply to Tom Ritchford
    Tom Ritchford:
    What a shame it requires Windows... after being a professional programmer for 25 years, I still don't own a Windows machine (and I've written hundreds of thousands of lines of C++ too...)

    I don't exactly understand why you did this, either. Seems like there's absolutely no need for it as the code is pure C++. Care to explain?

    RTFA:

    "Of course, you don’t have to use my skeleton solution, but it’s there for you if you’d prefer. For the Linux folks out there, you may use the mostly equivalent GTK skeleton solution."

    Good thing its not a test of reading comprehension!

  • Foobar (unregistered) in reply to JamesCurran
    JamesCurran:
    Foobar:
    Right, it actually does compile. The code that had the problem looked like this:
    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    Now I don't know if that's a compiler bug or really intended in C++

    No that was intended... Or to be more exactly, it doesn't fall under the hack which allowed the first sample. A text literal is a const char[], which can be implictly, converted to a const char* or (if necessary) a char*. Note that the last conversion only applies to a text literal. So, the expression (blah?"foo":"bar") as a whole is a const char*. (actually, since both literals are the same size not conversion at all is needed, so it might even consider it a "const char[3]". Regardless, the expression as a whole is not a text literal, and therefore cannot be converted to a "char*".

    Now, the funny thing is that if I replace blah by a constant 1, GCC won't throw an error on this code, which is why I wrote it as I did.

    JamesCurran:
    No, I'm saying that C is a different language from C++ because while they're syntactically similar (though not identical), the way the two languages are used, especially when it comes to allocation, error handling and standard libraries, means that C knowledge can't just be transferred into C++ knowledge and C++ knowledge can't just be transferred into C knowledge. You need to learn both languages, and thus they're distinct.

    For the most part, I agree, but one must consider degrees of distinction. There is about a 80-90% overlap in "C Knowledge" and "C++ Knowledge". And much of the 10-20% difference is C++ not allowing the kind of idiomatic/sloppy programming that C only allows because the first C compilers had to run in 32K and were more concerned with code generation than syntax checking.

    I'll agree that C allows many, hmm, suboptimal expressions to be used. But many of those are considered legacy and bad style. C++, however, in many cases encourages sloppy and obfuscated programming. Sloppy programming would include making declarations at random places, obfuscation would be for example operator overloading.

    JamesCurran:
    Well, I can extend that. Any well written C++ program will be compilable with a C compiler.

    When your definition of a well written C program is something that compiles with a C++ compiler, well, then the argument is lost before it even started.

    Oh well, you suddenly went from competent debater to idiot/jackass.

    I'm sorry you see it that way. My point is still that they're not the same language. Many of the "features" of C++ which I dislike are also the ones that make things not compile with a C compiler.

    JamesCurran:
    No, my definition of a well-written C program has nothing to do with C++ compiler. Apparently, you don't really understand the concept of "well-written". Let's take for example, the code you posted before:
    extern int blah;
    void foo(char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    The fact that this passes through a C compiler does NOT mean it is "well-written". Properly, it should be:

    extern int blah;
    void foo(const char *);
    void bar()
    {
            foo(blah?"foo":"bar");
    }
    

    No, I completely agree there, the prototype for foo() should indeed have const for its parameter.

    But there are a fewseperate issues here and I think we're talking a bit besides each other:

    1. C and C++ are syntactically similar.
    2. C code does not compile with a C++ compiler, even if you claim that C code that does not compile with a C++ compiler is not well written.
    3. C and C++ programming is vastly different.

    I think for 1 and 3, we agree or mostly agree.

    For 2, I think we don't. Let's take the most common C as C++ showstopper: Implicit casts from void *. I really, really can't agree that explicitly casting the return value of malloc() makes code more "well written."

    Let's take another example:

    int getclass()
    {
       int class = 0;
    
       return class;
    }
    

    Is this code badly written?

    JamesCurran:
    "const" has been part of the C language for 18+ years, so it's about time you actually learned this language you defend so much.

    Oh, I do know, use and preach the use of const very much!

    I think you misunderstood me a bit. I didn't defend the non-use of const, I was saying that these differences mean that a C program does not compile as C++.

    JamesCurran:
    In fact, "const" was added to the language at the same time the parameters were added to function declarations (Previously, that would have had to be written as "void foo();") So you can't even fall-back on claiming that it's legacy K&R C code --- The sample was written wrong to start with.

    I do not know when const was added to C, but I do know about parameter-less prototypes (obviously). However, string literals are still char * in C, so the sample is not wrong. Wrong in C++, yes, not wrong in C.

    JamesCurran:
    C++ has a lot of "features" over C which makes code much harder to read, much harder to maintain and overall puts the code in a lot worse condition. Though I don't expect you to agree.

    No Comment --- I'll just let the readers judge with is "harder to read, much harder to maintain and overall puts the code in a lot worse condition"

    C++:

    main()
    {
    std::string A = "Hello";
    std::string B = "world";
    std::string C = A +", " + B + "!";
    cout << C << endl;
    }

    C:

    main()
    {
    const char A[] = "Hello";
    const char B[] = "world";
    char * C = malloc(strlen(A) + strlen(B) + 4);
    // That's +2 for comma-space, +1 for bang, and +1 for NUL
    if (C == NULL)
    exit();
    strcpy(C,A);
    strcat(C, ", ");
    strcat(C,B);
    strcat(C, "!");
    printf("%s\n", C);
    free(C);
    }

    Besides that I think that your C code is ugly, I'll just give one competition: Count the amount of function calls in the C and the C++ code, tell me which functions are called and where to find them. Thanks :)

  • Foobar (unregistered) in reply to EvanED
    EvanED:
    Foobar:
    No, any remotely decent compiler will tell you when you use a variable uninitialised.
    #include <stdio.h> 
    
    int main() {
      int* x;
      printf("%d", *x);
    }

    This code compiles without warnings on GCC 3.4 and 4.1 (gcc -W -Wall and g++ -W -Wall). I would consider both of them to be "remotely decent".

    Well, that code will give you at least one warning with -Wall:

    warning: control reaches end of non-void function

    The reason you're not warning about the usage of the uninitialised variable is that GCC cannot perform this without optimisations being enabled, if you compile with at least -O, you also get this warning:

    warning: 'x' is used uninitialized in this function

    And besides that, I have my own opinion of the quality of GCC 3.4 and 4.1, and it's not good, but I'll spare you from hearing about that ;)

    EvanED:
    As for the rest, I guess again we disagree. I don't find myself needing to know the type of a variable and not being able find the declaration at all frequently, and think the readibility and other benefits outweigh those times.

    Nothing wrong with disagreeing. Maybe the difference is that I work a lot with code other people wrote, while I guess you mostly work with code you wrote? Forgive me if I am wrong :)

    And while finding the type might not be something you do that often, it's still something you do and have to do when you validate code. Another thing you also must do is to be able to distinguish declarations from statements, something which is harder to do than is necessary in much of the code I read and validate.

  • JamesCurran (cs) in reply to Foobar
    Foobar:
    Besides that I think that your C code is ugly

    Really? And I thought I was being clear and explicit. At least I didn't do anything like

    strcat(strcat(strcat(strcpy(C, A), ", "), B), "!");

    And I firmly believe if read by someone completely unfamiliar with either language, the function of the C++ is more readily understood. ("Strcpy? Shouldn't that have a vowel somewhere?")

    How would you write it prettier?

    Count the amount of function calls in the C and the C++ code, tell me which functions are called and where to find them.
    A valid question -- to a point. Ignore the C++, and just tell me how many you think there are in the C code. Exactly how complex is malloc or strcat or printf? And even if you know the complicity of your library now, who's to say it won't change on the next release of your compiler. Those simple function names hide vastly complicated code --- exactly as the + in my C++ example.

    Now, to get back to the original argument, in most contexts, I'd consider "C/C++" to mean "The C & C++ family of languages" inwhich I'd include C# and Java.

    P.S.: I appreciate the change in tone. I appologize for the "jackass" comment.

  • Fred (unregistered) in reply to JamesCurran

    How would you write it prettier?

    sprintf

    Now, to get back to the original argument, in most contexts, I'd consider "C/C++" to mean "The C & C++ family of languages" inwhich I'd include C# and Java.

    Yow.

  • EvanED (cs) in reply to Foobar
    Foobar:

    I'll agree that C allows many, hmm, suboptimal expressions to be used. But many of those are considered legacy and bad style. C++, however, in many cases encourages sloppy and obfuscated programming. Sloppy programming would include making declarations at random places, obfuscation would be for example operator overloading.

    Operator overloading is another place where I disagree, at least when used judiciously. Is it obfuscation to allow +, -, etc. to work on a complex number or a rational number class? If anything, I think having to write cplx_add(a, b) instead of a + b is obfuscation.

    Or for a less conventional approach, what about using operator overloading to essentially build an abstract syntax tree of an expression? For instance, I have a program that I wrote that interfaces with a SAT solver, and you have to feed it expression trees for expressions like "(x and y) or (x and z)". In C, generating this tree would look something like this:

    expr* form_x = mk_var("x");
    expr* form_y = mk_var("y");
    expr* form_z = mk_var("z");
    expr* x_and_y = mk_and(form_x, form_y);
    expr* y_and_z = mk_and(form_y, form_z);
    expr* formula = mk_or(x_and_y, y_and_z);

    Or, if you prefer,

    expr* formula =  mk_or( mk_and( mk_var("x"), mk_var("y") ),
                            mk_and( mk_var("y"), mk_var("z") ));

    Which looks a little like an ugly version of Lisp if you're into that.

    Whereas I can write

    Formula form_x = Formula::var("x");
    Formula form_y = Formula::var("y");
    Formula form_z = Formula::var("z");
    Formula formula = Formula::Create( (form_x && form_y) || (form_y && form_z) );

    (I wouldn't indent it like that if it weren't for the max line length here)

    Actually right now I can be even more brief:

    Formula formula = (Formula("x") && Formula("y")) ||
                        (Formula("y") && Formula("z"));

    but I think that's gone a little to far; too many implicit conversions.

    In the above the differences between the C version and my version are relatively small, but imagine how the C version would look for what I can write as

    Formula ans = ((var == lb + x*s) &&
                   (0 <= x) &&
                   (x < (ub-lb)/s) &&
                   (lb <= var) &&
                   (var <= ub));

    Some would probably say this is an abuse of operator overloading, but IMO this has dramatically improved the readability of the code. And that's really one of the goals of overloading.

    Finally, operator overloading is almost required if you want to be able to write generic functions like, say, min or max that operate on both primitives and user-defined types.

    For 2, I think we don't. Let's take the most common C as C++ showstopper: Implicit casts from void *. I really, really can't agree that explicitly casting the return value of malloc() makes code more "well written."

    I agree there.

    Besides that I think that your C code is ugly, I'll just give one competition: Count the amount of function calls in the C and the C++ code, tell me which functions are called and where to find them. Thanks :)

    This is a downside; C++ hides code behind your back. For instance, I'm not even sure of the answer to that question, because there are a number of places that I'm not sure whether constructors are implicitly called.

  • Foobar (unregistered) in reply to JamesCurran
    JamesCurran:
    And I firmly believe if read by someone completely unfamiliar with either language, the function of the C++ is more readily understood. ("Strcpy? Shouldn't that have a vowel somewhere?")

    Someone unfamiliar with aeither language should not be writing in either language. It would just lead to seriously buggy code. And that's an uncommon and not very useful scenario anyway, IMO. It's much more likely that someone who knows both languages is gonna read it.

    Both examples are pretty simple, so there's not much room for confusion there anyway. The problem really arises when you've got really complex C++ code, deeply nested inheritance, multiple functions with the same name, operator overloading, etc. Debugging your way through a complex C++ program is very hard and I'd say it's bordering impossible to follow the flow of a complex C++ program without a debugger... which in my line of work is something you aren't always afforded.

    JamesCurran:
    How would you write it prettier?

    Well, most of the code would go towards a utility function I wouldn't mind having seen in the C library. Someone might consider the utility function "hairy" or "complex", but IMO (and I don't intend to be rude when I say this) that would just show that the person doesn't know C. Anyway, here goes:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    char *malloc_sprintf(const char *format, ...)
    {
            va_list args;
            int len;
            char *ret;
    
            va_start(args, format);
            len = vsnprintf(0, 0, format, args);
            va_end(args);
    
            ret = malloc(len+1);
            if (ret)
            {
                    va_start(args, format);
                    vsprintf(ret, format, args);
                    va_end(args);
            }
    
            return ret;
    }
    
    int main()
    {
            const char A[] = "Hello";
            const char B[] = "world";
            char *C;
    
            C = malloc_sprintf("%s, %s!", A, B);
            if (C)
            {
                    printf("%s\n", C);
                    free(C);
            }
    
            return 0;
    }
    
    JamesCurran:
    Count the amount of function calls in the C and the C++ code, tell me which functions are called and where to find them.
    A valid question -- to a point. Ignore the C++, and just tell me how many you think there are in the C code. Exactly how complex is malloc or strcat or printf? And even if you know the complicity of your library now, who's to say it won't change on the next release of your compiler. Those simple function names hide vastly complicated code --- exactly as the + in my C++ example.

    Yes, but those function calls all have a clearly defined function and are clearly distinguished from things that are not function calls. I was also only talking about functions called directly from the code.

    In the C code I count 8 function calls, and that took me no time or brain power to figure out.

    In the C++ code I count 11, and that number took a little bit more thinking and time to get to.

    JamesCurran:
    Now, to get back to the original argument, in most contexts, I'd consider "C/C++" to mean "The C & C++ family of languages" inwhich I'd include C# and Java.

    So, if someone writes on his CV that he knows C/C++, would you consider him competent for a C# programming job? ;)

    JamesCurran:
    P.S.: I appreciate the change in tone. I appologize for the "jackass" comment.

    Ditto. I guess sometimes I just get too passionate about a discussion ;)

  • EvanED (cs) in reply to Foobar
    Foobar:

    Well, that code will give you at least one warning with -Wall:

    warning: control reaches end of non-void function

    Yeah, that's because I am a C++ programmer. ;-) I saw the warning when I compiled with gcc and fixed it, but then forgot to paste the updated version.

    The reason you're not warning about the usage of the uninitialised variable is that GCC cannot perform this without optimisations being enabled, if you compile with at least -O, you also get this warning:
    warning: 'x' is used uninitialized in this function

    Interesting... I think I knew that GCC requires optimizations sometimes but forgot. That's... kind of stupid. I realize they are trying to speed up compilation, but if you use -W -Wall (which itself is somewhat silly... shouldn't -Wall turn on, I dunno, "all" warnings?) I want warnings.

    And besides that, I have my own opinion of the quality of GCC 3.4 and 4.1, and it's not good, but I'll spare you from hearing about that ;)

    I don't know how good GCC is on an objective scale. There are some things that I know that other compilers do better, but they tend to be somewhat esoteric stuff like produce nice output with -S. And they seem to have better C and C++ language support then, say, VC++ 6, though that isn't exactly a gold standard of compilation either. They're also by far the biggest compiler in the OSS community, which means that they are almost a necessary target for some apps.

    Nothing wrong with disagreeing. Maybe the difference is that I work a lot with code other people wrote, while I guess you mostly work with code you wrote? Forgive me if I am wrong :)

    It's sort of a mix. I definitely do mostly work with my own code, but I'm also doing a fair amount of stuff with existing C++ code bases, and I have done some Linux kernel programming in the past. (That was when I missed RAII in C...)

    (Speaking of which, there's a WTF to submit to the site.

  • Icelight (unregistered) in reply to AC
    AC:
    Tom Ritchford:
    What a shame it requires Windows... after being a professional programmer for 25 years, I still don't own a Windows machine (and I've written hundreds of thousands of lines of C++ too...)

    I don't exactly understand why you did this, either. Seems like there's absolutely no need for it as the code is pure C++. Care to explain?

    RTFA:

    "Of course, you don’t have to use my skeleton solution, but it’s there for you if you’d prefer. For the Linux folks out there, you may use the mostly equivalent GTK skeleton solution."

    Good thing its not a test of reading comprehension!

    Yeah, geez, if it was he'd probably already have won by now...

  • CaptchaFillrOutr (unregistered) in reply to Foobar

    [quote user="Foobar"] C:

    main()
    {
    const char A[] = "Hello";
    const char B[] = "world";
    char * C = malloc(strlen(A) + strlen(B) + 4);
    // That's +2 for comma-space, +1 for bang, and +1 for NUL
    if (C == NULL)
    exit();
    strcpy(C,A);
    strcat(C, ", ");
    strcat(C,B);
    strcat(C, "!");
    printf("%s\n", C);
    free(C);
    }
    [/quote]

    Besides that I think that your C code is ugly, I'll just give one competition: Count the amount of function calls in the C and the C++ code, tell me which functions are called and where to find them. Thanks :) [/quote]

    It's doubly funny because the C++ version he posted allocates several extra strings that it doesn't need. As well as the fact that the C version should have used snprintf()

    He kind of proved your argument with the A + ", " + B + "!" yay for allocating 3 extra string objects!

  • DoOver (unregistered) in reply to mabinogi

    You don't actually work in the real world, do you? Purely academic?

  • SomeNerdyGuy (unregistered)

    For the contest, is writing a C (or C++) app that acts as a web server legal? Then we could write our own hacky web servers with a browser for the UI. Sounds fun!

  • Sin Tax (unregistered)

    There are two WTF ways to approach this: the academic way, and the enterprisey way.

    The academic way follows this scheme.

    1. Realize that a four-function calculator is a string processing problem, which calls for a parser.
    2. Write a grammar for the FFC.
    3. Write a parser generator that produces a parser for the FFC grammar.
    4. Write a AST manipulating tool that reflects the state of the display.
    5. Write Your Own Variant of CAML With Some Cecil And Ruby Thrown In Language (YOVOCWSCARTL), a programming language which you expect will be especially well suited to writing parser generators for four function calculator grammar parsers.
    6. In which you then bootstrap 4 and 3.
    7. Designing an OS to run the whole shit is optional.

    The enterprisey way follows this scheme:

    1. A FFC is an important tool, hence reliability is a major issue. We therefore need a clustered solution with failover.

    2. Each key of the calculator is best represented as a class, each key subclassing the "Key" class. As you may want to have the numeric keys colored differently, there should also be intermediate classes NumericKey and OperatorKey. Same for the display, which should be implemented as 7-segment LCD displays.

    3. For interface, we need some sort of AJAX.

    4. The generation of numeric displays should be a HTML TABLE of generated images. The generation of these images is delegated to a developer group specialising in Perl, and they will use Boutell's GD library from CPAN. The value for each digit will be FTP'd to the interface/display server (running LAMP on a Beowulf cluster of some sort) from the main calculator server farm. The images for the keys are of course generated from a specification received from the Key class value objects stored on the calculator server farm. This is done through a webservice, with each key represented internally in an EJB. Pressing a key calls the webservice, which calls a method on the EJB, which sends an XML representation of the Key value object on the JMS queue to the BPM engine. Did I forget to say the calculator server farm needs to run BEA WebLogic Integration? The actual operation of the calculator is modelled in the BPM language of WLI. The resulting display is continuously posted by FTP'ing (again, XMLized representations of) Digit value objects to the interface/display server. A cron job here ensures that the when the response page is generated, the correct digits will be displayed.

    To develop this calculator, we need three developer teams, one for the LAMP frontend, and one for the BEA backend, and one for developing the integration layer inbetween. Two DBAs, fifteen PMs, two application architects, an operations architect, a managerial advisory board, top-level external contractors/consultants for developing the Business Logic in WLI, and then add the usual 25% overhead to be safe. For running the FFC service system, we need a 24/7 manned operations centre, with two Unix admins (Solaris and Linux experts) at any time, a "service desk" call centre, and a backup tape robot with its own support department. And of course we'll have to have the whole project setup ISO 9000 and ISO-20000/ ITIL certified, this adds another ten man-years right there, plus exorbitant consultant fees. Changing the color of a key of course will require modification at all levels, and require thorough change management and redeployment of 90% of the systems. Such a moderate change should be achievable within a window of 6 months, give or take a planning period latency of at least three months.

    Before this Four Function Calculator enters service, 85% of the components will be obsolete, unfunctional or out of support, and will need replacement, modification and/or therapy. Which brings us to phase 2 of the Four Function Calculator service, a project one or two orders of magnitude larger than phase 1 described above, due to the rising cost of Enterprise-grade hardware and software, and other factors. Cost of Phase 1: Zillions. Cost of Phase 2: Gagazillions.

    -Sin Tax (perfect enterPrisey IT Architect (pePITA) wannabe.)

    Captcha: sanitarium

  • Sin Tax (unregistered) in reply to seaturnip
    seaturnip:
    I suppose your analogy is not completely worthless... provided the elephant has just eaten the apple in question.

    Corollary: C++ works by quickly making shit out of C.

    -Sin Tax

  • dkf (unregistered) in reply to Sin Tax
    Sin Tax:
    The academic way follows this scheme. 1. Realize that a four-function calculator is a string processing problem, which calls for a parser. 2. Write a grammar for the FFC.
    Ah, you've gone somewhat wrong there already. The true academic way is to realize that all computing machines are turing-equivalent and that therefore you should carry out the string processing using a Turing Machine, preferably using unary arithmetic.

    Another way is to pass the expression (with a suitable wrapper) into a C compiler and have that dynamically compile up a module that contains a function that evaluates the expression. Then you can dlopen() the linked module, get the address of the function from within it, call it, and get the value out, assuming the user hasn't done an "expression insertion attack" on you. (Come to think of it, I've done very similar things in the past. But at least the function there was computationally heavy and came from a large FORTRAN library and the C code was application-specific glue...)

    For added fun, write the function in such a way that the code is actually C++ and Boost and requires a full implementation of both in order to build correctly. Indeed, if you do it right, you'll have constructed something that is incredibly slow to operate and which stands a chance of breaking utterly when deployed almost anywhere. :-)

  • JamesCurran (cs) in reply to CaptchaFillrOutr
    It's doubly funny because the C++ version he posted allocates several extra strings that it doesn't need. As well as the fact that the C version should have used snprintf()

    He kind of proved your argument with the A + ", " + B + "!" yay for allocating 3 extra string objects!

    I do? Where?

    I'm assuming that you mean that 'A +", "' creates one new string, while the "+ B" would create another, and the '+"!"' create the third, but, as I didn't show the implementation of std::string, there's no way to state that definitely. It's quite possibly to write a implementation of string::operator+ which would allocate only one string new string for the series of pluses. (And yes, I have written such an implementation).

  • JamesCurran (cs) in reply to Foobar
    Foobar:
    JamesCurran:
    Now, to get back to the original argument, in most contexts, I'd consider "C/C++" to mean "The C & C++ family of languages" inwhich I'd include C# and Java.
    So, if someone writes on his CV that he knows C/C++, would you consider him competent for a C# programming job? ;)
    If he wrote that on his resume, I wouldn't consider him competent for anything.
  • BAReFOOt (unregistered)

    Man... "olympiad" is the term for THE TIME BETWEEN TWO OLYMPIC GAMES!

    So when can we expect the actual games?

  • nobody (unregistered)

    How about a calculator that generates emails and waits for the answer? For example, multiplying 12 by 25 would generate a jpeg of 25 lines of 12 matches (or were they toothpicks) on a wooden table, send it to Rain Man, and wait for the answer. Of course, the calculator doesn't work when Wappner is on.

  • JL (unregistered) in reply to Sarni
    Sarni:
    A GUI is required? Fuck, fuck, fuck. Who the fuck needs a GUI? And then fucking C/C++? I think I'll pass.
    That's a pity. You could have easily written a horrendous console application, then teamed up with someone else willing to write a GUI that screen-scraped it. That would be plenty WTF. Then your only problems would be (1) how to split the laptop (hint: the left half has more keys) and (2) what to put on your resume ("Yes, I won a programming contest. No, I won't tell you which one.").
  • Evilwumpus (unregistered)

    Graah! I know C# but not C/C++! It's a pity, because I had a great plan: The program would count the number of buttons pressed, and use that to determine what test case it's on, and what should be displayed. Alternatively, I could have it display the answer but immediately clear the display, because there is no requirement that the answer be outputted long enough to be readable.

  • Daniel Beardsmore (cs) in reply to BAReFOOt
    BAReFOOt:
    Man... "olympiad" is the term for THE TIME *BETWEEN* TWO OLYMPIC GAMES!

    Hm, I don't think the dictionary definition or common usage would agree with you on that one (lots of counterexamples for you there).

  • Sin Tax (unregistered) in reply to dkf
    dkf:
    Sin Tax:
    The academic way follows this scheme. 1. Realize that a four-function calculator is a string processing problem, which calls for a parser. 2. Write a grammar for the FFC.
    Ah, you've gone somewhat wrong there already. The true academic way is to realize that all computing machines are turing-equivalent and that therefore you should carry out the string processing using a Turing Machine, preferably using unary arithmetic.

    (...)

    For added fun, write the function in such a way that the code is actually C++

    No academic implementation would EVER be in C++, would it?

    However, modifying one of the van Wijngaarden grammar examples in [Cleaveland&Uzgalis 1977] to do the job should be fairly easy, and convincing as well. And yes, this would imply unary arithmetic.

    -Sin Tax

    [Cleaveland&Uzgalis 1977] J. Craig Cleaveland and Robert C. Uzgalis Grammars for programming languages Elsevier (1977)

  • Jon Raynor (unregistered)

    Here's a good (bad) design that maybe someone with some free time can implement:

    From C++ invoke via COM and VB6 Component DLL, then use the .NET Framework COM Interop to invoke a C# component. Write unmanaged code in C# to do the work. Pass results back to VB and then back to C++ through the component DLL layers.

    This should get you on the medal stand.

  • Doh (unregistered)

    I'll just put all the code in one line to gain the extra points.

    captcha: pinball

  • Random (unregistered) in reply to EvanED
    EvanED:
    Turambar:
    Foobar:
    Another thing I see scaringly often by C++-programmers-turned-C is something like:
    x = new char[strlen(y)];
    strcpy(x, y);
    

    And then after a while, someone taps me on the shoulder, asks me if I know why the new operator would be crashing and if it is a bug in the operating system. Of course the new that's crashing is the one after the code I wrote.

    I'm a "C/C++ programmer who actually doesn't know C", could you enlighten me on why that code doesn't work?

    strlen returns the number of characters in the string not including the terminating null, so there isn't enough space allocated by new for strcpy to append the null.

    Boom, instant buffer overrun.

    You forgot to mention, "new is not a keyword, so it's treated as an identifier. Boom, instant syntax error." The correct answer to their question as to why the new operator is crashing would be "what new operator? all operators in C have existed since 1978."

  • cindy (unregistered)
    Comment held for moderation.

Leave a comment on “The Worse Than Failure Programming Contest”

Log In or post as a guest

Replying to comment #:

« Return to Article