I thought I knew c++



  • This won't compile and I don't know why. I'm sure it's some basic c++ thing that I should know but I'm stumped. Oh don't worry this isn't actual code. Just a test I typed up.

     

    int globalvar;

    class testme
    {
    public:
            testme();
            testme(int a);
            void incr();
    };

    int main()
    {
            testme myClass();
            //testme myClass(4); // using this constructor will make it compile
            myClass.incr();
            return 0;
    }

    testme::testme()
    {
            globalvar=0;
    }

    testme::testme(int a)
    {
            globalvar=0;
    }

    void testme::incr()
    {
            globalvar++;
    }

     

    What is my WTF?  What is special about the default constructor?



  • @goldsz said:

    This won't compile and I don't know why. I'm sure it's some basic c++ thing that I should know but I'm stumped. Oh don't worry this isn't actual code. Just a test I typed up.

     

    int globalvar;

    class testme
    {
    public:
            testme();
            testme(int a);
            void incr();
    };

    int main()
    {
            testme myClass();
            //testme myClass(4); // using this constructor will make it compile
            myClass.incr();
            return 0;
    }

    testme::testme()
    {
            globalvar=0;
    }

    testme::testme(int a)
    {
            globalvar=0;
    }

    void testme::incr()
    {
            globalvar++;
    }

     

    What is my WTF?  What is special about the default constructor?

    Bolded the culprit.

    There's a rule for parsting C++ that says that if something can be parsed as a declaration, it must be parsed as a declaration.  Any statement "typename name ()" can be parsed as the declaration of a no-args function, so it must be parsed as such, rather than the definition of an object with default-constructor initialization.

    Try either of "testme instance = testme();" or "testme instance;" -- both are equivalent and do what it looks like you want.  
     



  • Thanks for clearing that up. However that brings up the question:
    You can declare a function in the body of another function??



  • You can declare functions inside other functions; the declaration will be visible only within that function.  You can't define a function inside another function as far as I know.

    [owen@verdandi c-wtf]$ cat foo.c
    #include <stdio.h>

    int foo () {
      printf("In foo()\n");
      return 42;
    }
    [owen@verdandi c-wtf]$ cat main.c
    #include <stdio.h>

    int main () {
      int foo ();

      foo ();

      return 0;
    }
    [owen@verdandi c-wtf]$ gcc -W -Wall -pedantic -std=c99 -c foo.c -o foo.o
    [owen@verdandi c-wtf]$ gcc -W -Wall -pedantic -std=c99 -c main.c -o main.o
    [owen@verdandi c-wtf]$ gcc *.o -o main
    [owen@verdandi c-wtf]$ ./main
    In foo()
    [owen@verdandi c-wtf]$

     



  • Shenanigans! Thanks, that's interesting to know.



  • @Angstrom said:

    You can declare functions inside other functions; the declaration will be visible only within that function.  You can't define a function inside another function as far as I know.

    While I don't believe the C spec includes this (although I haven't taken the time to wade through it and find out), more or less every major C implementation allows you to define functions inside other functions. This creates some fascinating trickery when taking a pointer to that function (a truly evil trick known as a "trampoline" is required to get the variable bindings correct).

    A significant amount of code in the real world relies on this feature. It is mostly the kind of old, low-level code that you have probably been using every day. It's kinda gross but it's there.



  • Do you care to explain any of this trampolining or a good use for defining a function in a function? I've used pointers to functions but I've always defined them in the normal fashion.



  • @goldsz said:

    Do you care to explain any of this trampolining or a good use for defining a function in a function? I've used pointers to functions but I've always defined them in the normal fashion.

    In other languages, where this is possible, it's usefull because the inner function sees the variables of the outer function. For example, if it was possible in C, we could write something like this:

     

    int countNonBlanks(char *s) {
      char *p;
      int count;

      void incP() {
        do {
          p++;
        } while (isspace(*p));
      }
     
      count=0;
      p=s;
      while (*p) {
         count++;
         incP();
      }

      return count;
    }
     

    Granted, this is not an impressive example where this looks very desirable. In fact, in OO languages, it's rather useless and it's use would probably indicate the "functional decomposition" antipattern.
     



  • @ammoQ said:

    In other languages, where this is possible, it's usefull because the inner function sees the variables of the outer function. For example, if it was possible in C, we could write something like this:

    ....

     not an impressive example where this looks very desirable. In fact, in OO languages, it's rather useless and it's use would probably indicate the "functional decomposition" antipattern.
     

     

    Ok I'm on the same page as you. I understand this concept. I've had to use lisp variants before. I just couldn't think of using it in c.



  • @goldsz said:

    Do you care to explain any of this trampolining[...]?

    A trampoline is a trick used by the compiler in the generated assembly code. You really have to study it closely to appreciate why it's necessary in C (most other languages wouldn't need it) and why it's just so sick and twisted.

    It involves code that generates other executable code at runtime...



  • @Angstrom said:

    You can declare functions inside other functions; the declaration will be visible only within that function.  You can't define a function inside another function as far as I know.

    I'm not certain I understand what you're trying to say; are you claiming that it is valid C++ syntax to write functions withing funcitons? That the following code would be valid?

    int outer()
    {
    int inner()
    {
    return 1;
    }

    return inner();
    }

    This does of course not compile (testing on MSVC8). In C++, when we wish to use nested functions, we have to go though an inner class. Nested functions are invalid C++ syntax.



  • No (though,as asuffield pointed out, most compilers will accept it and do something sane), you're not allowed to write (define) functions inside functions.  A function declaration in C or C++ doesn't define the function, just the name of the function.  Take a look at the example I posted: the line inside main() that reads "int foo ();" declares a function "foo" taking no arguments and returning int.  The definition is in a separate compilation unit, foo.c.



  • Hmm, ok, you have specified a function signature of the same name as an already existing function without defining the body for the signature. Then you invoke the function of the same name as the defined signature through a vanilla call. How would that allow you to manipulate the function call? It is not as being nefarious with function pointers, I don't see the example you provided above as doing anything beyond superfluously forward-declaring the name of a global function. :-?

    Edit: you're doing something creative with the object code using C99 mode of the GCC compiler? Ok, but wouldn't this be very non-standard code really risking undefined behaviour and begging portability issues?



  • There's no header declaring the foo() function, so in main.c the symbol is undeclared even though another compilation unit defines the function -- except in main(), where there's a local declaration of the global function foo().

    The original question was why the line

      Sometype name ();

    inside a function didn't declare and define a variable called "name"; my example is just a short demo of what's really happening with that syntax (C mandates that, because it looks like a function declaration, it *is* a function declaration; C++ inherits that rule):.

    The key concept is that C and C++ separate declaration from definition for symbols.  Declarations can have a different scope from the definition, provided the definition makes sense.  In C++, this occasionally leads to unexpectedly declaring a function when you meant to define a local variable.

    And, no, actually... the combination of options I used are intended to prevent me from accidentally doing non-standard things.  It's not perfect, but the code as written is also valid in ISO C90; I just use C99 mode as a matter of habit.



  • @Mikademus said:

    @Angstrom said:

    You can declare functions inside other functions; the declaration will be visible only within that function.  You can't define a function inside another function as far as I know.

    I'm not certain I understand what you're trying to say; are you claiming that it is valid C++ syntax to write functions withing funcitons? That the following code would be valid?

    int outer()
    {
    int inner()
    {
    return 1;
    }

    return inner();
    }

    This does of course not compile (testing on MSVC8). In C++, when we wish to use nested functions, we have to go though an inner class. Nested functions are invalid C++ syntax.

    Most non-MSVC compilers would accept this code, at least in C mode (it may be rejected in C++ when not under extern "C"). It's not perfectly portable, but it's pretty close.



  • Well, whattayaknow. So for once MSVC is the more standard-compliant compiler, and this time to my detriment, since I often miss the functionality to use nested functions. Yeah, I make use of inner classes, but is IS more verbose. I really wish nested functions were legal C++ constructs.

     /me goes off to attempt to cleverly leverage ' extern "C" '
     



  • I'd still love to see an example of using this where it makes sense.



  • @Mikademus said:

    Well, whattayaknow. So for once MSVC is the more standard-compliant compiler, and this time to my detriment, since I often miss the functionality to use nested functions.

    Since neither the C nor C++ specifications place any limits on what extensions a compiler can implement, it's not a "standards-compliance" thing - more like "standards-pedantic", if such a term existed (referring to the habit of not implementing things that are not in the specification).
     



  • @asuffield said:

    @Mikademus said:

    Well, whattayaknow. So for once MSVC is the more standard-compliant compiler, and this time to my detriment, since I often miss the functionality to use nested functions.

    Since neither the C nor C++ specifications place any limits on what extensions a compiler can implement, it's not a "standards-compliance" thing - more like "standards-pedantic", if such a term existed (referring to the habit of not implementing things that are not in the specification).
     

    I do not agree with this. If the compiler did not enforce the standard strictly then the code simply wouldn't be portable. The C++ Standard is in fact extensively specified, both positively and negatively, and though I will NOT try to find the particular passage in the Book now I do have a memory of reading that nested functions are not valid syntax. I even think it is written in "The C++ Programming Language". Further. over the last iterations MSVC has increasingly been removing extensions "for increased Standard conformance". Which is a Good Thing. Implementors should NOT be free to willy-nilly add extensions, and refraining from this to a stricter interpretation and thus better intercompatabilty is where C++ compilers have been moving for the last years.



  • @Mikademus said:

    If the compiler did not enforce the standard strictly then the code simply wouldn't be portable.

    Enforcing compliance with the specification does not cause code to become portable. There do not exist any strictly compliant compilers for C or C++, so you're going to have to test with each compiler you want to port to anyway. Cross-platform language specifications have always been an approximate thing.


    The C++ Standard is in fact extensively specified, both positively and negatively

    Both the C and C++ specifications have specified that certain syntactical structures should always generate an error (primarily to avoid ambiguity), but they do not place any limits on the kind of features you can add to a compiler - just on the range of syntax that you can use to do it. A compiler is free to define behaviour for any syntax that is not explicitly specified in the specification.

     

    and though I will NOT try to find the particular passage in the Book now I do have a memory of reading that nested functions are not valid syntax. I even think it is written in "The C++ Programming Language".

    I think that's just a comment that the specification doesn't include any syntax for nested functions.

     

    Further. over the last iterations MSVC has increasingly been removing extensions "for increased Standard conformance".

    Actually, it's all about breaking compatibility with other compilers. Microsoft wants it to be difficult to write cross-platform applications. They are fully aware that removing extensions does not have any impact on conformance with the C and C++ specifications. 

     

    Implementors should NOT be free to willy-nilly add extensions

    That's a matter of design choice. The designers of the C and C++ languages disagreed with you, which probably has something to do with why they created successful languages and you have not done so. Implementers are free to add extensions and are encouraged to do so. Those extensions which work out well tend to get added to the next revision of the language specification. Most of the changes in later versions of both were made in this fashion.

    It's basically the difference between the proprietary and community development styles. You are advocating that people should use the proprietary approach to language design. C and C++ (and many other languages) use the community style.



  • @asuffield said:

     

    Implementors should NOT be free to willy-nilly add extensions

    The designers of the C and C++ languages disagreed with you, which probably has something to do with why they created successful languages and you have not done so.  ... You are advocating that people should use the proprietary approach to language design. C and C++ (and many other languages) use the community style.

    WTF are you on?! I thought you were reasonable but scratch that. Bye.



  • @asuffield said:

    The designers of the C and C++ languages disagreed with you, which probably has something to do with why they created successful languages and you have not done so. Implementers are free to add extensions and are encouraged to do so. Those extensions which work out well tend to get added to the next revision of the language specification. Most of the changes in later versions of both were made in this fashion.

    It's basically the difference between the proprietary and community development styles. You are advocating that people should use the proprietary approach to language design. C and C++ (and many other languages) use the community style.

    It should be noted that many successfull languages were created in a "proprietary" approach, e.g. Java. The success of C is most likely owned to the fact that it is easy to create a C compiler, thus C became ported to most platforms (and on most platforms, it has been the first language available); and since C is as close to assembler language as can be, it allows for writing fast executing code, which was important 10 or 20 years ago for about any code written. C++ is successfull because it is seen as the successor of C and has strong vendor support.

    Non-standard extensions to C are IMO much more of a problem than a chance. It really sucks when a C program does not compile without changes just because the target plattforms doesn't even like the C++ style comments. // this is a comment not every C compiler accepts 



  • @ammoQ said:

    It really sucks when a C program does not compile without changes just because the target plattforms doesn't even like the C++ style comments. // this is a comment not every C compiler accepts 

    IIRC the C99 standard includes // comments. Of course if you're working on some weird platform, the compilers there may not be C99 capable.

     

    Anyway, short C++ question: is the following code valid C++ according to the standard? Most compilers I've run across seem to accept it... I also remember reading somewhere that declaring local structs/classes in functions is OK.

    void foo()
    {
      struct bar
      {
        static void a() { do_something(); }
      };
      bar::a();
    }



  • @cvi said:

    @ammoQ said:

    It really sucks when a C program does not
    compile without changes just because the target plattforms doesn't even
    like the C++ style comments. // this is a comment not every C compiler
    accepts 

    IIRC the C99 standard includes // comments. Of course if you're working on some weird platform, the compilers there may not be C99 capable.

    Not a weird platform, just some Unix box (AIX IIRC). 



  • class testme
    {
    public:
            testme();
    //        testme(int a);

    // do this way (this is not connected to current problem but will help you avoid other one)

            explicit testme(int a);
            void incr();
    };



  • @ammoQ said:

    @cvi said:

    @ammoQ said:

    It really sucks when a C program does not
    compile without changes just because the target plattforms doesn't even
    like the C++ style comments. // this is a comment not every C compiler
    accepts 

    IIRC the C99 standard includes // comments. Of course if you're working on some weird platform, the compilers there may not be C99 capable.

    Not a weird platform, just some Unix box (AIX IIRC). 

    AIX is a weird platform, as far as I'm concerned. It's probably the strangest proprietary unix still on the market.

    Nonetheless, it supports both C99 and // comments at least in 5.3, and possibly in older versions (I don't know off the top of my head when it was first added). Admittedly the C99 support is a bit buggy in places but // comments definitely work.

    When compiling with gcc, // comments should always be supported and full C99 features can be enabled with -std=gnu99. When using xlc, you will probably need to add -qlanglvl=extc99 to get it working right - the default is limited for no apparent reason.

    Of course, if this was AIX 4.* or something like that, I'm just going to laugh long and hard and be glad I don't have your job.



  • @asuffield said:

    AIX is a weird platform, as far as I'm concerned. It's probably the strangest proprietary unix still on the market.

    Nonetheless, it supports both C99 and // comments at least in 5.3, and possibly in older versions (I don't know off the top of my head when it was first added). Admittedly the C99 support is a bit buggy in places but // comments definitely work.

    When compiling with gcc, // comments should always be supported and full C99 features can be enabled with -std=gnu99. When using xlc, you will probably need to add -qlanglvl=extc99 to get it working right - the default is limited for no apparent reason.

    Of course, if this was AIX 4.* or something like that, I'm just going to laugh long and hard and be glad I don't have your job.

    Fortunately for me, I was just helping out in deploying an app on that machine. I do not regulary have to work on AIX. Since I'm used to the level of comfort I have in GNU/Linux (bash, vim etc.), AIX is a bit rustic to me.

    Yeah, I know that it's perfectly possible to install those GNU tools on AIX, but I can't do that on a machine I don't own.

    Thanks for the "-qlanglvl=extc99" hint, I'll try that should I ever have to touch that thing again.



  • @ammoQ said:

    @cvi said:

    @ammoQ said:

    It really sucks when a C program does not
    compile without changes just because the target plattforms doesn't even
    like the C++ style comments. // this is a comment not every C compiler
    accepts 

    IIRC the C99 standard includes // comments. Of course if you're working on some weird platform, the compilers there may not be C99 capable.

    Not a weird platform, just some Unix box (AIX IIRC). 

     
    1. AIX is a weird platform.

    2. If the program has BCPL style comments then it isn't a C program (as defined by the 1990 C standard).

     



  • @Mikademus said:

    Further. over the last iterations MSVC has increasingly been removing extensions "for increased Standard conformance". Which is a Good Thing. Implementors should NOT be free to willy-nilly add extensions,

     Perhaps you could make a submission to the C++ Standards committee, asking them to remove the text from the C++ Standard that says that implementations are free to add extensions that don't alter the behaviour of conforming programs?

     
    Also, I think you'll find that most of the 'extensions' being removed by MSVC are ones that DO alter the behaviour of conforming programs.


    Oh, and the real WTF is that the preview button is up the top of this page, and not even on-screen when you are typing the message!



  • @Old Wolf said:

    Perhaps you could make a submission to the C++ Standards committee, asking them to remove the text from the C++ Standard that says that implementations are free to add extensions that don't alter the behaviour of conforming programs?

    It would be ignored, perhaps as it should be, since the very idea of C++ is freedom for developers. I personally think that "extensions" should come only from revisions of the Standard and that the Standard would be revised somewhat less infrequently, but it isn't difficult to see that denying compiler makers the right to include changes not violating the language definition would go against the spirit and principals C++ is based on.

    I think you'll find that most of the 'extensions' being removed by MSVC are ones that DO alter the behaviour of conforming programs.

    That's a good way of putting it. And the REAL WTF is of course that Win32 programming requires the use of VC++ extensions, that is, afaik one cannot port Win32 code to compilers not supporting VC++'s extensions (unless linking to CV++-compiled static or dynamic libraries from the "real" code).



  • @Mikademus said:

    @Old Wolf said:

    Perhaps you could make a submission to the C++ Standards committee, asking them to remove the text from the C++ Standard that says that implementations are free to add extensions that don't alter the behaviour of conforming programs?

    It would be ignored, perhaps as it should be, since the very idea of C++ is freedom for developers. I personally think that "extensions" should come only from revisions of the Standard and that the Standard would be revised somewhat less infrequently, but it isn't difficult to see that denying compiler makers the right to include changes not violating the language definition would go against the spirit and principals C++ is based on.

    I think you'll find that most of the 'extensions' being removed by MSVC are ones that DO alter the behaviour of conforming programs.

    That's a good way of putting it. And the REAL WTF is of course that Win32 programming requires the use of VC++ extensions, that is, afaik one cannot port Win32 code to compilers not supporting VC++'s extensions (unless linking to CV++-compiled static or dynamic libraries from the "real" code).

     

    Balderdash.  I do it all the time, as my products cross-compile on Linux/Solaris/AIX/HPUX/what-have-you and Windows.  Including a bogus "stdafx.h" on the non-Windows platforms pretty much gets you out of the woods.  Of course, I'm not using WIN32-specific API calls, but that goes without saying--doesn't it?



  • @mrprogguy said:

    @Mikademus said:

    And the REAL WTF is of course that Win32 programming requires the use of VC++ extensions, that is, afaik one cannot port Win32 code to compilers not supporting VC++'s extensions (unless linking to CV++-compiled static or dynamic libraries from the "real" code).

     

    Balderdash.  I do it all the time, as my products cross-compile on Linux/Solaris/AIX/HPUX/what-have-you and Windows.  Including a bogus "stdafx.h" on the non-Windows platforms pretty much gets you out of the woods.  Of course, I'm not using WIN32-specific API calls, but that goes without saying--doesn't it?

    For most programmers including yours truly "Win32" means "using the Win32 API", which in turns boils down to "#include <windows.h>", which requires the VC++ language extensions. I assume you really understood this and was just being argumentative for the hell of it. Also, you do know that you can turn off precompiled headers, and then you won't need any ersatz stdafx.h's?


Log in to reply