|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#26 |
|
Messages: n/a
Hébergeur: |
On Thu, 18 Oct 2007 16:29:53 -0700, ymuntyan@gmail.com wrote:
> On Oct 18, 11:18 am, Eric Sosman <Eric.Sos...@sun.com> wrote: > > ymunt...@gmail.com wrote On 10/18/07 09:37,: > > No, 6.2.7p1 says they are *compatible* types, not that > > they are the *same* type. > > Well, the "compatible" there is italicized, I take it as > that's the definition of "compatible". In other words, it But the definition includes the rest of para 1, and the other paras referred to; it must, otherwise these statements, which are stated as requirements in the standard, would be inconsistent with the definition and thus no implementation of C would be possible. And we know it can't be the intent of the Standard writers to prevent all implementations and therefore all use of the language. (In spite of exaggerated and insulting conspiracy theories from some.) > says something like "Types are compatible if and only if > they are the same". And then it goes to explain what it > means for two types to be "the same". > Compatibility is deliberately weaker than being the same. If two types are the same they are compatible; if they are distinct, but are _sufficiently similar_ according to the specific rules given in the rest of para 1 and the other paras, they are compatible. Informally, compatibility of X and Y means that an (actual) X can safely be accessed as a Y and it will work. This means compatible types must have the same layout (representation) in storage, and types that don't have the same representation can't be compatible. However the converse (or inverse? I always forget) is not true: there are (pairs of) types that are required to have the same representation(s), but are still distinct types so that the compiler can (and usually must) diagnose type-mixings considered undesirable. > But it makes stuff like > > struct {int a; int b;} a; > struct {int a; int b;} *p = &a; > > illegal, or, more realistic, > > void callback (void *p) > { > struct {int a; int b;} *data = p; > /* ... */ > } > > void func (void) > { > struct {int a; int b;} data = {1, 2}; > call_something (callback, &data); > } > Indeed it does. Declare the struct tag, or a typedef for the untagged struct, once, somewhere visible to all uses -- which if it is used in multiple functions means the declaration must be at file scope. That's the rule. Or if you want to cheat, learn to live with the warnings and override the errors. That's the way it is. > // file.h > extern struct {int a; int b;} *a; > > It's impossible to actually define that 'a' if you include > the header into the C file; and it's possible all right if > you don't. Weird example of course, and it's why (it's a > hypothesis) this wasn't taken into account - nobody thought > about it or it was too much trouble to add it to the standard > comparing to the benefits. > Yes, that's a mildly unfortunate consequence of the rules adopted to handle the cases considered more important. This simple but fairly common case -- exactly one variable of or using the type -- can be done by preprocessor trickery, if init to 0 is OK: BLECH struct { blah blah } gorp; where BLECH is #define'd as extern for all #include's of file.h EXCEPT the one where you want to define the data; there is it #define'd empty, which makes this a tentative definition, and since there can't be another compatible declaration with initializer in that t.u. it becomes an actual definition, and the one definition needed. (Use a more mnemonic name, of course, depending on which characteristic you want to emphasize and document: something like ALLOC_OR_SHARE or something like GLOBAL_SINGLE_DATUM.) For init to non-0, but known, you can use a macro that generates either the correct initializer or no initializer. But more generally you indeed cannot have two anonymous struct types declared in the same t.u. with the same contents be the same type. - formerly david.thompson1 || achar(64) || worldnet.att.net |
|
|
|
#27 |
|
Messages: n/a
Hébergeur: |
On Oct 18, 4:18 pm, Eric Sosman <Eric.Sos...@sun.com> wrote:
> Cross-module compatibility addresses a nasty issue > that confronts many separately-compilable languages. If > the compiler processes module A on Tuesday and processes > module B on Wednesday, we can't really talk about a type > compiled in A being "the same" as a type declared in B. > And yet, we want A to create objects of type T and pass > them to B to be processed. Since A and B had separate > declarations for T they can't really have "the same" T, > so the Standard resorts to this notion of "compatibility" > to allow separately-compiled modules to agree on what a > T looks like. Does that mean that the compiler is obliged to use the same memory layout (i.e. same amount of padding in the same places) for two structs with identical fields declared in different translation units? What about if one of the fields has a different name (but the same type) in the two structs? If the answer to the first question is "yes", does that create practical problems when trying to link object files created with different C compilers (or the same compiler with different optimization or other settings)? > > -- > Eric.Sos...@sun.com |
|
|
|
#28 |
|
Messages: n/a
Hébergeur: |
Francine.Neary@googlemail.com wrote On 10/30/07 18:12,:
> On Oct 18, 4:18 pm, Eric Sosman <Eric.Sos...@sun.com> wrote: > >> Cross-module compatibility addresses a nasty issue >>that confronts many separately-compilable languages. If >>the compiler processes module A on Tuesday and processes >>module B on Wednesday, we can't really talk about a type >>compiled in A being "the same" as a type declared in B. >>And yet, we want A to create objects of type T and pass >>them to B to be processed. Since A and B had separate >>declarations for T they can't really have "the same" T, >>so the Standard resorts to this notion of "compatibility" >>to allow separately-compiled modules to agree on what a >>T looks like. > > > Does that mean that the compiler is obliged to use the same memory > layout (i.e. same amount of padding in the same places) for two > structs with identical fields declared in different translation units? > What about if one of the fields has a different name (but the same > type) in the two structs? If the struct tags are different, the types are different. You can test this for yourself: struct A { int i; } a = { 42 }; struct B { int i; } b; b = a; /* diagnostic required */ Since the two structs are of different types, they could in theory have different representations: The Standard requires common representations for only a few sets of types, and these are not among them. In practice, though, the compiler will process the `struct A' and `struct B' declarations with the same algorithm and get the same result (in the absence of things like `#pragma pack' and similar bletcherous botches). > If the answer to the first question is "yes", does that create > practical problems when trying to link object files created with > different C compilers (or the same compiler with different > optimization or other settings)? There *are* practical problems in linking objects from different compilers. As for option flags, if they make the compiler behave differently, then what you've really got is one piece of software that several different compilers. For example, if there's a `--pack-all-structs' option, you can expect trouble mixing modules compiled with and without it. -- Eric.Sosman@sun.com |
|
|
|
#29 |
|
Messages: n/a
Hébergeur: |
On 30 Oct 2007 at 22:32, Eric Sosman wrote:
> Francine.Neary@googlemail.com wrote On 10/30/07 18:12,: >> Does that mean that the compiler is obliged to use the same memory >> layout (i.e. same amount of padding in the same places) for two >> structs with identical fields declared in different translation units? >> What about if one of the fields has a different name (but the same >> type) in the two structs? > > If the struct tags are different, the types are different. > You can test this for yourself: > > struct A { int i; } a = { 42 }; > struct B { int i; } b; > b = a; /* diagnostic required */ > > Since the two structs are of different types, they could > in theory have different representations: The Standard requires > common representations for only a few sets of types, and these > are not among them. In practice, though, the compiler will > process the `struct A' and `struct B' declarations with the > same algorithm and get the same result (in the absence of > things like `#pragma pack' and similar bletcherous botches). I guess I was asking specifically about un-named structs in different translation units. Consider the following code: /* TU1.c */ void foo(struct { int a; }) { ... } /* TU2.c */ void foo(struct { int a; }); void bar() { struct { int a; } X; X.a=0; foo(X); } /* TU3.c */ void foo(struct { int a; }); void baz() { struct { int a; } Y; Y.a=0; foo(Y); } If I understood what you said upthread correctly, this will work just fine, though if foo were actually defined in TU2.c then there'd be a type-incompatibility and TU2.c wouldn't compile. Doesn't this force binary compatibility between objects of any unnamed types struct { int a; } in different translation units? (But not necessary between an object of a type struct { int a; } and an object of a type struct { int b; } ?) |
|
|
|
#30 |
|
Messages: n/a
Hébergeur: |
Francine.Neary@googlemail.com wrote:
> On 30 Oct 2007 at 22:32, Eric Sosman wrote: >> Francine.Neary@googlemail.com wrote On 10/30/07 18:12,: >>> Does that mean that the compiler is obliged to use the same memory >>> layout (i.e. same amount of padding in the same places) for two >>> structs with identical fields declared in different translation units? >>> What about if one of the fields has a different name (but the same >>> type) in the two structs? >> If the struct tags are different, the types are different. >> You can test this for yourself: >> >> struct A { int i; } a = { 42 }; >> struct B { int i; } b; >> b = a; /* diagnostic required */ >> >> Since the two structs are of different types, they could >> in theory have different representations: The Standard requires >> common representations for only a few sets of types, and these >> are not among them. In practice, though, the compiler will >> process the `struct A' and `struct B' declarations with the >> same algorithm and get the same result (in the absence of >> things like `#pragma pack' and similar bletcherous botches). > > I guess I was asking specifically about un-named structs in different > translation units. Consider the following code: > > > /* TU1.c */ > > void foo(struct { int a; }) Needs an identifier after the } -- let's call it tu1. > { > ... > } > > > /* TU2.c */ > > void foo(struct { int a; }); > void bar() > { > struct { int a; } X; > X.a=0; > foo(X); Diagnostic required. The declared type of the parameter to foo() is different from that of X, and no conversion is possible. You've got two untagged struct types in the same translation unit; the compatibility rule for untagged structs specifically requires separate translation units. Within one translation unit, each struct declaration introduces a new type, distinct from all other types. For structs with tags the scope rules apply: Two identically- tagged structs in disjoint scopes are different types, while two identically-tagged structs in overlapping scopes provoke a diagnostic. For untagged structs, the behavior is as if the compiler gave the first one an artificial tag like `#1', the next one `#2', and so on: Each untagged struct is a distinct type, no matter what the scope, and two such struct types can never be compatible. Some compilers will emit a ful warning about the declaration of foo(), pointing out that the struct type has "prototype scope." That is, the type goes out of scope at the end of the prototype, meaning that any similar struct you might declare elsewhere will be in a different scope and will not be of the same type. Thus, there is no way to write a correct call to foo() in the same translation unit because there is no way to declare an argument of the proper type. > } > > > /* TU3.c */ > > void foo(struct { int a; }); > void baz() > { > struct { int a; } Y; > Y.a=0; > foo(Y); Same problem as before: Two untagged structs in the same translation unit are two distinct types. > } > > If I understood what you said upthread correctly, this will work just > fine, though if foo were actually defined in TU2.c then there'd be a > type-incompatibility and TU2.c wouldn't compile. > > Doesn't this force binary compatibility between objects of any unnamed > types struct { int a; } in different translation units? (But not > necessary between an object of a type struct { int a; } and an object > of a type struct { int b; } ?) I think you should re-read 6.2.7p1, and then if necessary take a deep breath and read it yet again. Question 11.5 in the FAQ may also be ful. -- Eric Sosman esosman@ieee-dot-org.invalid |
|
![]() |
| Outils de la discussion | |
|
|