Teaching C++ WTF.



  • Okay, so I know I'm masochistic because I'm taking a C++ course at my local community college. Only to wonder if the instructor is going batshit.

    He knows I've done this stuff already (and I can prove it pretty easily) but its like pulling teeth to get a good grade out of this guy. Point and case, we had to write an application that took user input for the length of a side of a regular octagon, then provide the area of said octogon to 3 sig figs.. Simple, at least to the unaided eye.

    My Code

    #include <cstdio>
    // Octagon Side Coefficient.
    #define oct_side_coeff 4.828

    int main (int argc, char** argv)
    {
    int num_parsed; float side; // Number of arguments parsed by scanf and side length.
    do { printf("Length of side: "); num_parsed = scanf("%e",&side); } // Get a side length
    while (num_parsed != 1) // And keep doing so until we get one thats nice.
    printf("\nOctagon area = %.3e\n", ( oct_side_coeff ) * (side * side)); // then print it out all nice and pretty.
    return 0; // And be kind to the system.
    }

    Instructors code

    #include <iostream>
    using namespace std;
    #define octagon_multiplication 4.828

    void main ( void ) {
    float side = 0.;
    cout << "Length of side: ";
    cin >> side;
    cout << "Area = ";
    cout << precision(3) << (octagon_multiplication ) * ( side * side );
    cout << endl;
    return 0;
    }

    My code was marked down for these reasons:

    • Did not include >iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

    For these reasons, my code was called "Cute" and "Bloated". Upon actually checking the reference binary and /my/ binary... My binary was 500K, his was 100K. So, does C++'s compiler really add that much overhead for C's Standard IO? No, it was because I was using MS's compiler.

    This is from an instructor who seems to think that /all/ code should have the 'using namespace std' because (And I quote!) "Since there's so many variables you have to tell the compiler where all your variables are". This same instructor described #define s as "pre-set global variables". He has us do awkward things using the VS IDE (see: we don't just go "console app" we go "Empty workspace" and then add things BY HAND.) and is so lazy he can't just read the code and know it, no he has us tack onto the end what it produces. 'cin' stands for 'console in' and 'cout' stands for 'console out'. as in, that little funny blue-and-green box that comes up when you run from visual studio.

    We have no fundamental idea insofar of the following ideas:

    • Data structures
    • Pointers
    • The difference between uint, int and uint32
    • What public and protected variables are
    • What Global variables are and what they do (the instructor just hates them, no matter how they are used!)


  • To be fair, your code is C, there's nothing C++ about it, and it's possible that the assignment's requirements included using cin/cout (as proof that you've learned the iostream modifiers, among other things)...

    Also, any reason you #define'd oct_side_coeff rather than making it a const double?



  • @Indrora said:

    Okay, so I know I'm masochistic because I'm taking a C++ course at my local community college. Only to wonder if the instructor is going batshit.

    He knows I've done this stuff already (and I can prove it pretty easily) but its like pulling teeth to get a good grade out of this guy. Point and case, we had to write an application that took user input for the length of a side of a regular octagon, then provide the area of said octogon to 3 sig figs.. Simple, at least to the unaided eye.

     

    My Code

     #include <cstdio>
    // Octagon Side Coefficient.
    #define oct_side_coeff 4.828

    int main (int argc, char** argv)
    {
    int num_parsed; float side; // Number of arguments parsed by scanf and side length.
    do { printf("Length of side: "); num_parsed = scanf("%e",&side); } // Get a side length
    while (num_parsed != 1) // And keep doing so until we get one thats nice.
    printf("\nOctagon area = %.3e\n", ( oct_side_coeff ) * (side * side)); // then print it out all nice and pretty.
    return 0; // And be kind to the system.
    }
    I congratulate you for choosing the superior language, but if you're writing C, why take a C++ course? 

    Instructors code

    #include <iostream>
    using namespace std;
    #define octagon_multiplication 4.828

    void main ( void ) {
    float side = 0.;
    cout << "Length of side: ";
    cin >> side;
    cout << "Area = ";
    cout << precision(3) << (octagon_multiplication ) * ( side * side );
    cout << endl;
    return 0;
    }
    @C++ standard said:
    Section 3.6.1 (2): An implementation shall not predefine the main function. This function shall not be overloaded. It shall
    have a return type of type int
    , but otherwise its type is implementation-defined.

    My code was marked down for these reasons:

    • Did not include <iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

    Okay, three of the points are valid criticisms. If you're takeing a C++ course, use <iostream>, cin and cout instead of the C stuff. If your main function doesn't take any arguments, don't pretend it does.

    For these reasons, my code was called "Cute" and "Bloated".

    That's a rather odd concept of "bloat".

    We have no fundamental idea insofar of the following ideas:

    • What Global variables are and what they do (the instructor just hates them, no matter how they are used!)

     

     I would like to think that means he's not completely useless, but I'm afraid it just means he once read that global variables are evil and has no idea why.



  • @Indrora said:

    do { printf("Length of side: "); num_parsed = scanf("%e",&side); } // Get a side length
    while (num_parsed != 1) // And keep doing so until we get one thats nice.

    Christ, at least use some linebreaks and indentation. I hate to break it to you, but his code is much more readable than yours.

    His code wouldn't compile with any decent compiler, though. Oh yeah, and teaching that you should be "using namespace std" is TRWTF.



  • @Indrora said:

    My code was marked down for these reasons:

    • Did not include >iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

    Basically, you were writing C. He was grading C++.

    C++ is (mostly) backwards-compatible with C. That means *most* valid C programs are also valid C++ programs. That *does not* mean that C and C++ are the same language.

    If you already know C, which is a superior language to C++ IMHO, you shouldn't be taking a C++ class. Unless you just want to get a handle on how bloated and difficult C++ is.

    @Indrora said:

    This is from an instructor who seems to think that /all/ code should have the 'using namespace std' because (And I quote!) "Since there's so many variables you have to tell the compiler where all your variables are".

    Well, his reason is retarded. But I think it's safe to assume that 99% of C++ programs are, or should be, using the Standard Template Library.

    @Indrora said:

    This same instructor described #define s as "pre-set global variables".

    Close enough.

    @Indrora said:

    'cin' stands for 'console in' and 'cout' stands for 'console out'. as in, that little funny blue-and-green box that comes up when you run from visual studio.

    ... yes, that is a console.

    @Indrora said:

    We have no fundamental idea insofar of the following ideas:

    • Data structures
    • Pointers
    • The difference between uint, int and uint32
    • What public and protected variables are
    • What Global variables are and what they do (the instructor just hates them, no matter how they are used!)

    Pointers: more trouble than their worth. You should be using a language, any language, that doesn't require pointers. (C++ with the STL gets pretty close to this ideal, actually.)

    The difference between uint, int and uint32: If you've ever developed on a Classic Mac with 16-bit ints, you'd quickly learn to *always* specify the size of the int. Never assume, even something as basic as this.

    What Global variables are and what they do (the instructor just hates them, no matter how they are used!): That's not a bad tactic.



  • @Indrora said:

    My code was marked down for these reasons:

    • Did not include >iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

    Did not include error checking for "File Not Found" or "The Printer is on Fire"

    For these reasons, my code was called "Cute" and "Bloated". Upon actually checking the reference binary and /my/ binary... My binary was 500K, his was 100K. So, does C++'s compiler really add that much overhead for C's Standard IO? No, it was because I was using MS's compiler.

    This is something that has slowly driven me away from programming over the years.  11 lines of code produces a 100k executable!!  WTF?  In this day and age we can't create a compiler that's a little more intelligent and efficient?


  • @El_Heffe said:

    This is something that has slowly driven me away from programming over the years.  11 lines of code produces a 100k executable!!  WTF?  In this day and age we can't create a compiler that's a little more intelligent and efficient?

    But it's not just 11 lines of code -- it's 11 lines that you wrote, plus however many lines are in cstdio, plus however many lines are in the files it includes. You can't expect the compiler to let you use all that functionality but have it take up no space. And before you mention it, yes, most linkers nowadays strip out unused functions from the image file.

    It's also possible Indrora was compiling in debug mode without realizing it.



  • @El_Heffe said:

    In this day and age we can't create a compiler that's a little more intelligent and efficient?

    "In this day and age", RAM is dirt cheap. 100k is lemme see... approximately 1/42000th of my memory. And that's even assuming none of those pages are shared, in reality I'd wager it's using a lot less memory.

    You now need to demonstrate to me that this program, compiled (for example) 20 years ago, would take less than 1/42000th of the memory of a typical computer of the day. This is Step 1, known as "put up."

    If you can't show that, then you need to go to Step 2. We call that "shut up."

    I'd wager $50 that if you actually measured the software size as a proportion of RAM, you'd find that software now is less bloated than ever before. But... actual measure would defeat your nostalgia "things were better in my day" bullshit...



  • @Indrora said:

    void main ( void ) { 
    // ... snip ...
    return 0;
    }

     

    Wait, what?

    (Side note: The second "void" is meaningless.)



  • @Indrora said:

    For these reasons, my code was called "Cute" and "Bloated". Upon actually checking the reference binary and /my/ binary... My binary was 500K, his was 100K. So, does C++'s compiler really add that much overhead for C's Standard IO? No, it was because I was using MS's compiler.

    After fixing both codes (adding ';' after while in your case, changing main's type to int and moving precision definition to own line in his case), your binary is 8K and your instructor's is 12K when compiled with g++ and no optimization. If linking statically, yours is 600K and your instructor's is 1.2M.

    And remember: scanf doesn't move input stream's pointer if it fails (try giving your program an "a").



  • @blakeyrat said:

    if you actually measured the software size as a proportion of RAM, you'd find that software now is less bloated than ever before.
     

    I'm not sure this is a valid metric.

    Additionally, Heffe's point was to the ratio of compiled_bytes / source_bytes. If a few lines turn into 500K,then a non-trivial program might show similar ratio. I do not know if this is the overall case, though, as I've never done any significant desktop development, and the few things I've done with .Net always produced amusingly small dlls, despite the code reinventing a new standard for the concept of bloat.

     

    Edit
    It seems Buzer adequately demonstrated that binary size is all over the map.



  • @dhromed said:

    I'm not sure this is a valid metric.

    Well, whatever the valid measure is. Before you start griping about a problem, you first have to:

    1) Show that the problem exists

    2) Show that it's important enough, in relation to other problems, to require attention

    Even if number 1 is true, and it does exist, I doubt it's more important than, say, getting programmers to stop making shitty UI decisions. Or stop using insecure virus-vector languages and tools. (Like C and C++, for example.)



  • @Faxmachinen said:

    Oh yeah, and teaching that you should be "using namespace std" is TRWTF.
     

    The instructor might be trying to teach "C++" rather than "good C++" --- as the original author appears to have written his C++ by replacing the include of stdio.h with cstdio in his C code, there are some fundamentals to focus on first...

    The "clever" thing about using cstdio rather than stdio.h is that cstdio is supposed to put things in the std namespace, rather than messing up the global namespace.  But if the author is dead set on combining "printf should be in the std namespace rather than global" with "I like to call printf as if it's global rather than in the std namespace", then "using namespace std" is an, in the context, reasonably clean workaround for som incredibly silly self-imposed problems...  (The "solution" of using a Microsoft compiler under which it works anyway is slightly problematic --- as the code may be graded by someone who doesn't do that...)



  • @Indrora said:

    My code was marked down for these reasons:
    • Did not include >iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

     I'm going to have to agree with your teacher on pretty much all of these:

    1. C++ is not C -- so you should be using iostream and cin/cout, not cstdio.

    2. Variable initialization -- I'm kind of iffy on this.  Sometimes it's nice to make sure that you have some default value, but I don't do it every time.  I always do it for pointers, though, because that can lead to incredibly hard-to-find errors otherwise.

    3. Not having the std namespace is actually one reason your code shouldn't even compile -- it's only the nonstandard behavior of your compiler putting printf in the global namespace and not the std namespace that makes it even WORK.  Of course in general you shouldn't pull in whole namespaces -- you can pull in individual functions.  But it's generally not a problem until you start pulling in more than one whole namespace.

    4. Don't put argc and argv unless you actually use them; it's not required and it implies something that isn't true -- namely, it implies your code accepts and uses parameters.

     

    He has us do awkward things using the VS IDE (see: we don't just go "console app" we go "Empty workspace" and then add things BY HAND.) and is so lazy he can't just read the code and know it, no he has us tack onto the end what it produces. 'cin' stands for 'console in' and 'cout' stands for 'console out'. as in, that little funny blue-and-green box that comes up when you run from visual studio.

    I agree with all this too -- starting from a blank project as opposed to pre-generated code is a good skill to have.  And tacking expected output on to the program is very important for proper QA.  In real programming, the person QAing your project likely can't read code at all, plus of course, it's important to define the expected output in the event that your code doesn't actually produce that output (i.e. it's buggy).  Without expected behavior explicitly defined, it's difficult to say what's a bug and what's simply intended behavior.


    • What Global variables are and what they do (the instructor just hates them, no matter how they are used!)

     

    Good.  99.9% of the time, they are the wrong answer to the problem, and even in that 0.1% where they're as good as anything else, there are other options that work too.



  • @Cat said:

    2. Variable initialization -- I'm kind of iffy on this.  Sometimes it's nice to make sure that you have some default value, but I don't do it every time.  I always do it for pointers, though, because that can lead to incredibly hard-to-find errors otherwise.

    I only do it for iterators and pointers. For anything else it isn't important enough as it'll usually get a value soon enough anyways.
    @Cat said:
    Good.  99.9% of the time, [global variables] are the wrong answer to the problem, and even in that 0.1% where they're as good as anything else, there are other options that work too.

    Not good. He should be explaining why you shouldn't use them, not never use them. Same case as goto.



  • (Is this guy's name Jansen by any chance?)

    Did not use explicit 3 point floating precision

    Wait, what?

    This same instructor described #define s as "pre-set global variables"

    My C++ teacher can do worse: cin and cout are functions, with redirection operators. (We also used some stupid template with #define print cout << and #define read cin >>, and never learned STL and used huge static arrays whenever we needed a bunch of values.)

    (And you both suck for using #define instead of a constant.)



  •  

    like pulling teeth to get a good grade out of this guy

    Welcome to university.



  • @blakeyrat said:

    if you actually measured the software size as a proportion of RAM, you'd find that software now is less bloated than ever before..

     

    So, let's see.   My car goes 20 miles on 1/20 the gasoline in the tank.  But, if I put in a much bigger gas tank, it can go 20 miles on only 1/60 of the gasoline in the tank.  Measuring mileage as a proportion of tank I now find that I get better mileage than ever before!!!!!   Thank you sir.  I am off to find a bigger gas tank.

     



  • @El_Heffe said:

    @blakeyrat said:

    if you actually measured the software size as a proportion of RAM, you'd find that software now is less bloated than ever before..

     

    So, let's see.   My car goes 20 miles on 1/20 the gasoline in the tank.  But, if I put in a much bigger gas tank, it can go 20 miles on only 1/60 of the gasoline in the tank.  Measuring mileage as a proportion of tank I now find that I get better mileage than ever before!!!!!   Thank you sir.  I am off to find a bigger gas tank.

     

    More like:

    "This 50lb suitcase makes my Taube unstable and liable to crash-- therefore I better not bring it onto this Airbus A-380!"

    @El_Heffe said:

    Filed under: Idiot

    Yes, obviously the person who's not kept awake at night by 100k of software bloat on their 4 GB computer is the idiot.



  • @blakeyrat said:

    More like:

    "This 50lb suitcase makes my Taube unstable and liable to crash-- therefore I better not bring it onto this Airbus A-380!"

    On the other hand, your A-380 is expected to carry slightly more than one passenger, which is exactly why the airline DOES have a problem with your 50lb suitcase.

    Software bloat still matters, because I'm expecting to run [i]several[/i] programs or even several operating systems on one computer.



  •  It has to be said that neither your code nor your instructors code would pass code review where I work.

     among other things:

    you: printf is in the std:: namespace; not readable;

    him: use of #define in C++; using (void) for parameterless functions; his code wouldn't compile

    both: not capitalising #define name



  • @wolff said:

    @blakeyrat said:
    More like:

    "This 50lb suitcase makes my Taube unstable and liable to crash-- therefore I better not bring it onto this Airbus A-380!"

    On the other hand, your A-380 is expected to carry slightly more than one passenger, which is exactly why the airline DOES have a problem with your 50lb suitcase.

    Software bloat still matters, because I'm expecting to run several programs or even several operating systems on one computer.

    Yeah, you're right! I could only run 48,000 instances of that application before I was short on memory-- I mean, it's not as if the OS shares code pages or anythi-- what? It does? Oh.

    Look, if software bloat causes *slow* software (not just big software), and if it's slow enough to affect the user experience like, say, Lotus Notes, then yes I agree with you entirely. But until it does, this is just another example of premature optimization. (Or, even worse, grumpy people complaining about other people's lack of premature optimization.) (Or, even even worse, grumpy people complaining about other people's lack of premature optimization *and* who are unaware of how modern OSes do memory management.)

    Take the program in this thread, the fixed version. It's a working, complete piece of software. Does it matter whether it takes up 1k, or 100k, or 1000k? No, no it does not. Would it be a complete and utter waste of time to tweak it to use less memory? Yes, yes it would.



  • @wolff said:

    @blakeyrat said:
    More like:

    "This 50lb suitcase makes my Taube unstable and liable to crash-- therefore I better not bring it onto this Airbus A-380!"

    On the other hand, your A-380 is expected to carry slightly more than one passenger, which is exactly why the airline DOES have a problem with your 50lb suitcase.

    Software bloat still matters, because I'm expecting to run several programs or even several operating systems on one computer.

    Airlines limit the weight of individual bags because the baggage handlers can't/won't lift them otherwise. I demand you include this factor in your analogy.



  •  Wow, the failboat's underway full steam ahead on this one for both parties!

    void main()? Smells like curry code. Old Turbo C++ "hacker". 



  • While I don't approve of your layout, I'd accept it as C++. The people here who insist you should use iostream based stuff, have lost it. Your teacher might like that you learn about it, but then the assignment should make that explicit. But in general, cstdio is a lot easier and more efficient than iostream. However, you should use it in order to understand it, just like you should understand the rest of the topics you mention (and a few more).Then you can decide for yourself what you like best. You should even have some experience with STL, which is TRWTF.



  • @Heron said:

    But it's not just 11 lines of code -- it's 11 lines that you wrote, plus however many lines are in cstdio, plus however many lines are in the files *it* includes.

    Absolutely wrong. The C headers do not generate code, they just declare types, constants, external variables and functions. The libraries they link to are small and most of it is included from the C++ libraries anyway (which can be pretty big), so in general using cstdio should lead to smaller binaries. Anyway, do a preprocessor expansion on the C-like program and on the C++-like program, and look at the differences...



  • @TGV said:

    Absolutely wrong. The C headers do not generate code, they just declare types, constants, external variables and functions. The libraries they link to are small and most of it is included from the C++ libraries anyway (which can be pretty big), so in general using cstdio should lead to smaller binaries. Anyway, do a preprocessor expansion on the C-like program and on the C++-like program, and look at the differences...

    And of course you're going to claim that constants, external variable references, function declarations, and so on add exactly zero bytes to the executable size? Don't be silly.

    At any rate, you missed my point. Specifically, it's not just 11 lines of code being compiled, it's a lot more. (Don't believe me? Do a preprocessor expansion on the code presented above... it's a lot more than 11 lines.)

    More specifically, once you #include something, you lose the right to complain "but I only wrote ten lines of code and the executable is ginormous!", because #include, well, includes more code.



  • @Cat said:

    @Indrora said:

    My code was marked down for these reasons:
    • Did not include >iostream>
    • Not initializing all my variables at the start
    • Did not include "using namespace std"
    • inclusion of argc and argv
    • not using cin and cout
    • Did not use explicit 3 point floating precision

    2. Variable initialization -- I'm kind of iffy on this.  Sometimes it's nice to make sure that you have some default value, but I don't do it every time.  I always do it for pointers, though, because that can lead to incredibly hard-to-find errors otherwise.

    Initializing variables at the start is simply a way to shut the compiler up.  By intentionally not initializing a variable until you have something productive to put in it, compiler warnings become much more meaningful.  It also tends to shrink the scope of locals, which is almost always a good thing.



  • @Indrora said:

    For these reasons, my code was called "Cute" and "Bloated". Upon actually checking the reference binary and /my/ binary... My binary was 500K, his was 100K. So, does C++'s compiler really add that much overhead for C's Standard IO? No, it was because I was using MS's compiler.

    So, the next thing to do is to run "dumpbin /HEADERS" (or "objdump -h", depending on toolchains available) on both the executables, and let's see where the space is going.  I can think of two likely possibilities:

    1) Different debug info amounts and/or formats between your two programs because of different compilers.

    2) Maybe you've linked statically to the C library and he's linked dynamically to his?

    Post the results back here if you get a chance.

     



  • @Jaime said:

    Initializing variables at the start is simply a way to shut the compiler up.  By intentionally not initializing a variable until you have something productive to put in it, compiler warnings become much more meaningful.  It also tends to shrink the scope of locals, which is almost always a good thing.

     

    In general, initializing variables is most certainly not done just "to shut the compiler up."

    I assume you are referring to the situation where you have a variable that is always set to the result of some other computation and is guaranteed to be unaccessed by any other thread until that initial computation has been executated. In a case like that then, yes, I agree that variable initialization is probably unnecessary, but I don't know that I'd call it unwise.

    Of course, I would also argue that you should never have a variable with nothing "productive to put in it" in the first place. (I realize you're probably talking about a C-style function where you put all the declarations at the beginning of a function but might not use them until somewhere late in the function body.)



  • @too_many_usernames said:

    @Jaime said:

    Initializing variables at the start is simply a way to shut the compiler up.  By intentionally not initializing a variable until you have something productive to put in it, compiler warnings become much more meaningful.  It also tends to shrink the scope of locals, which is almost always a good thing.

     

    In general, initializing variables is most certainly not done just "to shut the compiler up."

    I assume you are referring to the situation where you have a variable that is always set to the result of some other computation and is guaranteed to be unaccessed by any other thread until that initial computation has been executated. In a case like that then, yes, I agree that variable initialization is probably unnecessary, but I don't know that I'd call it unwise.

    Of course, I would also argue that you should never have a variable with nothing "productive to put in it" in the first place. (I realize you're probably talking about a C-style function where you put all the declarations at the beginning of a function but might not use them until somewhere late in the function body.)

    Of course I'm talking about "a C-style function where you put all the declarations at the beginning of a function but might not use them until somewhere late in the function body".  Where a variable is initialized can be important, especially if the procedure has a loop and the variable has to be re-initialized for each iteration of the loop.  If you only type the initialization when you get to the part of code where it needs to be initialized, then this type of procedure will fail gracefully.  With the "initialize on top" mentatily, forgetting to re-initialize at the beginning of the loop will become a bug.  With the "initialize when ready" mentality, forgetting to initialize at the beginning of the loop will become a compiler warning.  "Initialize on top" was a strategy that was useful in the days before good IDEs, but its usefulness is minimal today.  Initializing everything at the beginning of the procedure should be looked at with the same disdain as Hungarian Notation.



  • @Jaime said:

    Where a variable is initialized can be important, especially if the procedure has a loop and the variable has to be re-initialized for each iteration of the loop.

    Of course, that leaves me wondering why you don't just [i]declare[/i] the variable at the beginning of the loop, too. (I know there are cases where you might need it declared outside, but if it's something you're resetting every time through the loop, you should most likely be declaring it inside the loop.)

    Declaring it inside the loop introduces no additional overhead, but it does keep the scope of the variable restricted so you don't make stupid mistakes.

    I'm of the "declare and initialize variables when you need them, and not before" mentality; I think declaring every variable at the top of a function is generally silly (whether or not you initialize them).



  • Without refudiating the idea that optimizing to minimize executable footprint shouldn't be done unless/until profiling suggests that the status quo will cause problems:

    Between the drivers, OS, applications, and everything else, the computer you're using has code written by thousands, if not tens of thousands, of different coders running on it right now. How well do you think it would perform if not one of them ever cared about the difference between 1k of code and 10k of code? Or 100k or 1000k?



  • @Heron said:

    @Jaime said:
    Where a variable is initialized can be important, especially if the procedure has a loop and the variable has to be re-initialized for each iteration of the loop.
    Of course, that leaves me wondering why you don't just declare the variable at the beginning of the loop, too. (I know there are cases where you might need it declared outside, but if it's something you're resetting every time through the loop, you should most likely be declaring it inside the loop.) Declaring it inside the loop introduces no additional overhead, but it does keep the scope of the variable restricted so you don't make stupid mistakes. I'm of the "declare and initialize variables when you need them, and not before" mentality; I think declaring every variable at the top of a function is generally silly (whether or not you initialize them).

    The same pinheads that teach initialize up top, also teach declare up top.  The instructor from the OP seems to be one of those pinheads.  ANSI C89 somewhat constrains where variable declarations can go and some people take these constraints further and restrict declaration to the beginning of a procedure.  My advice is always to declare with the smallest possible scope and initialize as late as possible.


  • @Rootbeer said:

    Without refudiating the idea that optimizing to minimize executable footprint shouldn't be done unless/until profiling suggests that the status quo will cause problems: Between the drivers, OS, applications, and everything else, the computer you're using has code written by thousands, if not tens of thousands, of different coders running on it right now. How well do you think it would perform if not one of them ever cared about the difference between 1k of code and 10k of code? Or 100k or 1000k?

    No one is suggesting that you never care.  Good sense dictates that you only optimize when there is an actual problem.  One reason for which is that some optimizations break other optimizations.  For example, static linking could potentially nullify benefits of some shared memory strategies.  If everybody statically linked for speed, it could result in an overall speed decrease.


  •  TRWTF is this entire thread



  • @Heron said:

    And of course you're going to claim that constants, external variable references, function declarations, and so on add exactly zero bytes to the executable size? Don't be silly.

    At any rate, you missed my point. Specifically, it's not just 11 lines of code being compiled, it's a lot more. (Don't believe me? Do a preprocessor expansion on the code presented above... it's a lot more than 11 lines.)

    More specifically, once you #include something, you lose the right to complain "but I only wrote ten lines of code and the executable is ginormous!", because #include, well, includes more code.

    I'm precisely going to claim that constants don't take up extra space, and external references neither. They are just there for the compiler and linker administration. Basically, the only thing that generates code in a C compiler is a function with a body. C++ is a bit different, but including cstdio doesn't change the size of the executable (the .o is something else; the linker's administration is in there).

    Thought experiment: what happens if you include the same header twice?



  • @TGV said:

     

    Thought experiment: what happens if you include the same header twice?



    If the header has an include guard, nothing. If the header does not have an include guard, then a ton of errors.


  • @Indrora said:

    He has us do awkward things using the VS IDE (see: we don't just go "console app" we go "Empty workspace" and then add things BY HAND.)
     

    Hang on.   What all does it take to create a console app in Visual C++? I don't think I've ever had to do that--most of my VC++ work is with building DLLs--but I know in Delphi it's a simple compiler directive.  You throw an {$APPTYPE CONSOLE} into the main unit and that's all it takes.  What do you have to do BY HAND to create a VC++ console app?



  • I'm precisely going to claim that constants don't take up extra space, and external references neither.

    External references take up no space, you say?

    [code]$ cat test-noextern.cpp
    int main()
    {
    return 0;
    }
    $ g++ test-noextern.cpp -o test-noextern
    $ ls -l test-noextern
    -rwxr-xr-x 1 heron heron 8481 2010-09-14 10:18 test-noextern[/code]

    And now with a single external int:

    [code]$ cat test.cpp
    extern int foobar;

    int main()

    {

    return foobar;

    }

    $ cat foobar.cpp

    int foobar = 0;

    $ g++ test.cpp foobar.cpp -o test-extern

    $ ls -l test-extern

    -rwxr-xr-x 1 heron heron 8547 2010-09-14 10:19 test-extern[/code]

    Now I admit my math is a little rusty, but I'm pretty sure 8547 > 8481... Go ahead, try it for yourself. (For the curious, -O2 shrinks test-extern by seven bytes, and bloats test-noextern by nine bytes.)

    Oh, and for even *more* fun, try this one:

    [code]$ cat test-const.cpp
    const int foobar = 0;
    int main()
    {
    return foobar;
    }[/code]

    Guess what? It's bigger than test-noextern by some 41 bytes!

    Perhaps by "constants" you meant "#defines", in which case you would be correct in the strictest sense; merely #include-ing a header containing #defines won't increase the size of your executable... unless you start *using* those #defines, at which point all bets are off.

    Basically, the only thing that generates code in a C compiler is a function with a body.

    That depends on how you define "code". Executable instructions? Sure, but that's not the only thing that matters. const char*s take up space, for example, even if you don't use them.

    Thought experiment: what happens if you include the same header twice?

    Most headers are specifically designed to prevent double-inclusion (using #ifdef). In a general sense, however, including the same header twice (e.g. by removing the double-inclusion protection) will often cause compiler or linker errors. In fact, come to think of it, even *with* double-inclusion protection, you can still end up with linker errors... (Define a const char*, or any variable, in a header protected by #ifdefs. #include that header in both test-extern.cpp and foobar.cpp, and try to compile the executable. Bad design, yes, but it can happen nonetheless. I ran into it when I was converting a mountain of #defines to consts.)

    Now I suppose you're going to say "include a header twice which only declares some functions or externs". That has the same effect as merely declaring the function twice in a row:

    [code]int myfunction();
    int myfunction(); // redundant declaration, the compiler will remove or ignore it
    [/code]

    In that case you'd be correct, but declarations are not the only things headers contain. (Write an unguarded header containing only "class Foo {};" and #include it twice, see what happens. Or if you prefer straight C, do it with a struct instead, same effect.)



  •  @Mason Wheeler said:

    Hang on.   What all does it take to create a console app in Visual C++? I don't think I've ever had to do that--most of my VC++ work is with building DLLs--but I know in Delphi it's a simple compiler directive.  You throw an {$APPTYPE CONSOLE} into the main unit and that's all it takes.  What do you have to do BY HAND to create a VC++ console app?

     Set the option that says to create an exe and not a lib or dll, which should be the default and add a cpp file with the main function in it.

     



  • @Mason Wheeler said:

    Hang on.   What all does it take to create a console app in Visual C++? I don't think I've ever had to do that--most of my VC++ work is with building DLLs--but I know in Delphi it's a simple compiler directive.  You throw an {$APPTYPE CONSOLE} into the main unit and that's all it takes.  What do you have to do BY HAND to create a VC++ console app?

    You don't have to do anything at all, other than create blank files to put your code in. No configuration changes are necessary.



  • (For the curious, -O2 shrinks test-extern by seven bytes, and bloats test-noextern by nine bytes.)

    I know it's poor form to quote myself, but I realized that, as previously mentioned, my math is rusty, and I was wrong:

    [code] -rwxr-xr-x 1 heron heron 8547 2010-09-14 10:19 test-extern
    -rwxr-xr-x 1 heron heron 8554 2010-09-14 10:22 test-extern-O2
    -rwxr-xr-x 1 heron heron 8481 2010-09-14 10:18 test-noextern
    -rwxr-xr-x 1 heron heron 8490 2010-09-14 10:22 test-noextern-O2
    [/code]

    test-extern is actually seven bytes *larger* with -O2, not smaller.



  • @Heron said:

    @Mason Wheeler said:

    Hang on.   What all does it take to create a console app in Visual C++? I don't think I've ever had to do that--most of my VC++ work is with building DLLs--but I know in Delphi it's a simple compiler directive.  You throw an {$APPTYPE CONSOLE} into the main unit and that's all it takes.  What do you have to do BY HAND to create a VC++ console app?

    You don't have to do anything at all, other than create blank files to put your code in. No configuration changes are necessary.

    So you get a console by default?  All right, then what do you have to do to get an app that doesn't create a console?



  • @Mason Wheeler said:

    So you get a console by default?  All right, then what do you have to do to get an app that doesn't create a console?

    Depends on what you're going for. Win32 app? Click "win32 app" when you're creating your project. There's even an "empty project" option, so you get the win32 settings without any clutter. Background service? I'd probably go with win32 app still, and just not open a window, since I'd likely need windows APIs and such. Not really sure offhand what else you might want...



  • @Heron said:

    @Mason Wheeler said:

    So you get a console by default?  All right, then what do you have to do to get an app that doesn't create a console?

    Depends on what you're going for. Win32 app? Click "win32 app" when you're creating your project. There's even an "empty project" option, so you get the win32 settings without any clutter. Background service? I'd probably go with win32 app still, and just not open a window, since I'd likely need windows APIs and such. Not really sure offhand what else you might want...

    Basically, in Windows, there's a flag in the PE header that creates a console for your app if it's set.  If it's set, a console will pop up when you run the program, even if it's a GUI app.  (This can be very useful for certain debugging cases.)

    In Delphi, you add a compiler directive that turns this flag on, or leave it out to not set the flag.   Whether or not you have a GUI is a completely different matter; that's based on whether or not you create any forms.  You can create a Service, or a simple data-processing app, that doesn't have a console or a GUI.  I'm basically just wondering what the mechanism is for turning the console flag on or off in VC++.  Apparently it's something elaborate, since the OP was complaining about having to do it all BY HAND...



  • @Mason Wheeler said:

    I'm basically just wondering what the mechanism is for turning the console flag on or off in VC++.  Apparently it's something elaborate, since the OP was complaining about having to do it all BY HAND...

    Maybe toggling that flag in an existing application is difficult, I don't know, but the OP was complaining about having to create an empty project and... do something he doesn't specify to enable a setting that's enabled by default (that is, make it a console app). Sounds like user error, to me.



  • @Faxmachinen said:

    teaching that you should be "using namespace std" is TRWTF




    Teaching "always anything" is almost always wrong. In college I was also taught to "always #include stdio.h" - the reason was because our professor didn't want to teach, or didn't know, what it really meant to include a library. I learned that on my own, when I had some actual work to do.



    Right now I'm dealing with a VB codebase where for some reason, everything is declared "ByVal" even when passing the reference is really what they want. They will seriously make a copy of an object, mess with it, return the changed object, and copy the changes back into the original object... when they could just pass a reference. Someone told them to always use "ByVal" in function declarations, and didn't ever tell them when to not use it and why and what it all means.


    This is typical of college professors. One of them once told me why... he basically said "All through your life, people will lie to you, and as you get older, the lies will become closer to the truth, but absolute truth can not actually be taught. In college, [i]it is our job to tell you the lies that people expect you to know when you graduate[/i]. Real life will teach you the truth." He's teaching you theory - in the real world, his code is slightly better because it is more readable - but this can not be taught, because "readable" is not clearly defined - readability can not be objectively measured, and so he can not teach it to you, because you can't be fairly graded on it.


    This idea that something must be objectively measurable in order to be taught is a real problem with programming classes - but it makes programming classes possible. I could never teach you what I have learned in 25 years on the job - I couldn't even teach you the concepts, at least not in a way that I could be sure you learned it.

    TRWTF is this post editor.



  • @Mason Wheeler said:

    I'm basically just wondering what the mechanism is for turning the console flag on or off in VC++.  Apparently it's something elaborate, since the OP was complaining about having to do it all BY HAND...

    Set Project Properties -> Linker -> System -> SubSystem to Console.

    It's not that elaborate, although somewhat hidden away. But it's not like it's something you would be doing all the time anyway.



  • @jasmine2501 said:

    They will seriously make a copy of an object, mess with it, return the changed object, and copy the changes back into the original object... when they could just pass a reference. Someone told them to always use "ByVal" in function declarations, and didn't ever tell them when to not use it and why and what it all means.

    Hey, nothing wrong with functional programming.

    One of our teachers didn't teach us functional programming (apparantly, he didn't know it existed), but he liked to have globals with names like "tau" and "N". He had a background in physics.


Log in to reply