tags:

views:

478

answers:

6

The following code compiles on a C++ compiler.

#include<cstdio>
int main()
{
struct xx
{
 int x;
 struct yy
 {
  char s;
  struct xx *p;
 };
 struct yy *q;
};

Would there be any difference in behavior while compiling with a C compiler?
i.e. would there be any compiler error?

A: 

Well, cstdio needs to be referred as stdio.h. As for the structure, the struct-keyword is not required in C++.

You don't really define struct members, but pointer members, so it seems plausible that it should work in either case.

e8johan
A: 

I just tested it with slight modifications and the gcc compiler

struct xx {
        int x;
        struct yy { char s; struct xx *p; };
        struct yy *q;
};

int main() { return 0; }

Compile with gcc

$ gcc test.c
test.c:3: warning: declaration does not declare anything

I compiles but gives a warning. Since my C is too rusty can't say any more.

Otto Allmendinger
A: 

Based on my brief research and the error message posted by Otto, it appears that C doesn't allow structures to be general-purpose namespace containers like C++ classes and structures are (naturally, because C doesn't even support classes). So you can't nest structure definitions in C. You would have to declare the inner structure outside of the outer structure declaration like this:

struct yy
{
        char s;
        struct xx *p;
};
struct xx
{
    int x;
    struct yy *q;
};

I see that the structures cross-reference each other. So if this is even possible in C, you may have to pre-declare the later structure with a line like:

struct xx;

(above both other declarations).

BlueMonkMN
Mutually recursive structures are possible in C. They are done just as you say, with a forward declaration.
Nate C-K
+2  A: 

Here are some changes (thanks to AndreyT):

Obviously you have to change the headers to make this compile. But even then, this seems not to be standard C as AndreyT pointed out. Nonetheless will some compilers like gcc still compile it as expected and only issue a warning. Likewise, Microsoft doesn't seem to interpret the standard too strictly:

"Structure declarations can also be specified without a declarator when they are members of another structure or union"

To make it standard C you have to turn your "struct yy" declaration into a definition. Then your code will be valid in C and in C++. To illustrate what is going on, I rewrote it in a, in my opinion, more comprehensible fashion and added a little test on what is going on.

#include<stdio.h>
#include<stdlib.h>

typedef struct xx xx;
typedef struct yy yy;

struct yy{ char s; xx *p;};

struct xx{ int x; yy *q;};

int main(){
    xx test;
    test.q = (yy*)malloc(sizeof(yy));
    test.q->s = 'a';
    test.q->p = (xx*)malloc(sizeof(xx));
    test.q->p->x = 1; 
    test.q->p->q = (yy*)malloc(sizeof(yy));
    test.q->p->q->s = 'b';
    printf("s: %c\n", test.q->s);
    printf("x: %d\n", test.q->p->x);
    printf("s: %c\n", test.q->p->q->s);
    return 0;
}

You can easily see, that you have a struct yy with a pointer to xx and the struct xx has a pointer to yy. This is equivalent to which can be written as followed in ansi-C:

#include<stdio.h>
#include<stdlib.h>

int main(){
    struct xx{
        int x;
        struct yy{
                    char s;
                    struct xx *p;
            } *q;   
            /*Here is the change to your example. You cannot have a structur 
              without a declactor inside of another structur! 
              Your version might due to compiler extensions still work*/
    };
    struct xx test;
    test.q = (struct yy*)malloc(sizeof(struct yy));
    test.q->s = 'a';
    test.q->p = (struct xx*)malloc(sizeof(struct xx));
    test.q->p->x = 1; 
    test.q->p->q = (struct yy*)malloc(sizeof(struct yy));
    test.q->p->q->s = 'b';
    printf("s: %c\n", test.q->s);
    printf("x: %d\n", test.q->p->x);
    printf("s: %c\n", test.q->p->q->s);
    return 0;
}

I compiled it with gcc and the following options:

gcc -ansi -pedantic -Wall -W -Wshadow -Wcast-qual -Wwrite-strings test.c -o

Both variants will have the same output

s: a 
x: 1
s: b

Now if you want to do the same in c++, your struct doesn't have to change but to use the inner struct you have to call the scope resolution operator (::) as follow:

test.q = (xx::yy*)malloc(sizeof(xx::yy));
test.q->s = 'a';
test.q->p = (xx*)malloc(sizeof(xx));
test.q->p->x = 1; 
test.q->p->q = (xx::yy*)malloc(sizeof(xx::yy));
test.q->p->q->s = 'b';
printf("s: %c\n", test.q->s);
printf("x: %d\n", test.q->p->x);
printf("s: %c\n", test.q->p->q->s);
Lucas
Well, your second "equivalent" example makes a critical modification that makes it valid C. The modification is the declaration of `q` member. The original code was not valid C, your modified on is.
AndreyT
AndreyT made this comment before I edited my answer.
Lucas
+3  A: 

The code in your post is obviously incomplete, just declarations, so it is hard to say anything conclusive.

On obvious difference is that in C++ the inner struct type will be a member of outer struct type, while in C language both struct types will be members of the same (enclosing scope). (BTW, was it your intent to declare them locally in main?).

In other words, in C++ the code that follows would have to refer to the structs as xx and xx::yy, while in C they would be just xx and yy. This means that the further code would look different for C and C++ and if it will compile in C++, it wouldn't compile in C and vice versa.

Added: C language prohibits declaring struct types inside other structs without declaring a member of that type. So, you struct yy declaration is illegal in C and will produce compiler diagnostic message. If you wanted your code to become legal in both C and C++, you'd have to combine the struct yy declaration with some data member declaration. In your case that could be pointer q:

struct xx {
        int x;
        struct yy {
                char s;
                struct xx *p;
        } *q;
};

The above is legal in both C and C++ (taking into account the differences I explained earlier), but your original declaration is not legal in C.

AndreyT
Good observation about c++. But are you sure that the struct yy declaration is illegal? It will compile just fine with gcc except the warning and also produces the expected behavior.
Lucas
Yes, I'm sure. C language grammar explicitly states that the "innards" of a `struct` must consist entirely of *declarators*. A `struct` declaration without a member declaration is not a *declarator*. GCC accepts it as an extension. GCC has lots of extensions. GCC is not good for "trying" for the purpose of checking the legality of the code. Comeau Online is much better for that purpose.
AndreyT
Thanks for the clarification. I changed my answer according to your remarks. Unfortunately I only get one upvote.
Lucas
A: 

C does not permit you to nest a type declaration inside a function definition. Also, to eliminate the warning about "does not declare anything, you should merge the declarations of type struct yy and member q. The following compiles with gcc with max warnings on:

struct xx
{
        int x;
        struct yy
        {
                char s;
                struct xx *p;
        } *q;
};

int main()
{
  return 0;
}
Norman Ramsey