2
int main()
{
    struct { int x; } foo;

    dostuff(&foo);
    return 0;
}

void dostuff(void *ptr)
{
    struct { int x; } *p = ptr;

    p->x = 5;
}

Dereferencing p is a strict-aliasing violation because the two unnamed structs cannot alias each other for they are not compatible. Now what problems could/would arise in such code?

Edit: I'm still not sure whether this defined behaviour since they don't have the same tag.

Assuming they are not compatible, would the following make any difference?

union u {
    void *v;
    struct {
        int x;
    } *p;
};

void dostuff(void *ptr)
{
    union u tmp = {.v = ptr};

    tmp.p->x = 5;
}
Pac0
  • 21,465
  • 8
  • 65
  • 74
netcat
  • 396
  • 1
  • 5
  • 14
  • It could be rather hard to maintain, imagine this stuff called across source files in a large project, then one definition gets changed, what happens to the other. – Matthew V Carey Dec 03 '14 at 00:38
  • 4
    If you violate strict aliasing, undefined behavior results, which means that literally anything can happen. – T.C. Dec 03 '14 at 00:42
  • 1
    If these two functions were in two different files, compiled by different compilers (or even different versions/settings of the same compiler), then you might have issues of different packing/alignment and such. – Lee Daniel Crocker Dec 03 '14 at 00:49
  • 1
    After reading the standard, I'm not sure if those structs are in fact incompatible. This might actually be defined. – 2501 Dec 03 '14 at 00:53
  • 1
    perhaps I'm wrong. But, as I see it, a is passing a pointer to some if its' data to a second function that saves that pointer. Seems ok to me. Of course, if I were wanting something like this, I would declare the struct format in a header file and have each .c file include that header file. – user3629249 Dec 03 '14 at 02:32
  • Just so we're clear. This is a theoretical question about technical corners of the 'C' standard, right? No one would do this, would they? – Persixty Dec 03 '14 at 08:26
  • Suggest the change to make the structs be called `struct a` and `struct b`. If the structs have compatible type there is no aliasing violation, but I think you wre trying to ask about aliasing violations, not about whether these structs are compatible. – M.M Dec 03 '14 at 10:12
  • @DanAllen strict aliasing violation is extremely common in real code. For example casting structs to another struct type that's a subset; or using casts to treat a char buffer as a series of integers. – M.M Dec 03 '14 at 10:12
  • @MattMcNabb Type compatibility is directly linked to aliasing. – 2501 Dec 03 '14 at 11:12
  • 1
    So if this is _undefined behaviour_, then the answer to my question is, bluntly put: __Just don't do it, it's UB and anything might happen__, correct? But now I'm not quite sure anymore whether it actually is undefined or not – netcat Dec 03 '14 at 11:12
  • 1
    @MattMcNabb Indeed. I can remember (about 23 years ago) my discovery that you could assign structs and have sport carving them up and passing pointers to members rather than sometimes onerous copy-out copy-back code you might write in other less enlightened programming languages. What I'm suggesting is potty is achieving it by the use of multiple declarations of anonymous `structs`. Please use casts and pointers as God intended people! – Persixty Dec 03 '14 at 11:31
  • @n.m.: What about the scenario where function F in compilation unit X is called from Y and Z; all three units define structures that are identical, but none have tags. Y and Z pass pass pointers to their structures to function F (in in unit X). Such pointer usage would satisfy the aliasing requirements in the Standard. Now the tricky bit: is there any way the header associated with X could declare function F inline for use within Y and Z, or is it impossible to achieve defined behavior without altering the source code to X and Y or requiring that F be invoked via external function call? – supercat May 18 '17 at 19:41
  • @supercat I'm not sure if your question has anything to do with the topic. Moreover I'm not sure now if my former comments here have any truth in them, so I have removed them. – n. m. could be an AI May 18 '17 at 21:53
  • @n.m.: The OP's question has to do with the use of pointers to two identical anonymous structure types declared in the same compilation unit, and your comment was wondering about why anyone would have need of such a thing. My intention was to offer a reason why the OP's scenario is a perfectly reasonable thing for code to want to do. – supercat May 18 '17 at 22:03
  • @supercat I'm not sure what you mean. I don't quite understand why the standard type compatibility rules are written the way they are. In my view they are needlessly complicated and possibly inconsistent. I don't see a way to use them in practice. – n. m. could be an AI May 18 '17 at 22:19

2 Answers2

0

As strange|crazy|surprising|paradoxical it may seem, struct { int x; } and struct { int x; } within one translation unit indeed declare not the same type, as stated in e. g. this comment.

would the following make any difference?

union u {
    void *v;
    struct {
        int x;
    } *p;
};

void dostuff(void *ptr)
{
    union u tmp = {.v = ptr};

    tmp.p->x = 5;
}

You didn't specify how dostuff() is invoked here, so you must have the same main() as in the first example in mind; given this, the types are still not compatible if the argument is declared in the same translation unit - the two declarations of the structure types again declare distinct types, regardless of one of them being contained within a union.
Moreover, this second version of dostuff() reinterprets void *v as struct … *p; since the C standard does not guarantee that a pointer to void has the same representation as a pointer to a structure type, this usage is not strictly conforming.

Community
  • 1
  • 1
Armali
  • 18,255
  • 14
  • 57
  • 171
  • IIRC the C standard says that every pointer to any data object can be stored to a `void *` reference and this would contradict your last statement. AFAIK this is always guaranteed to work: `X * a = ...; void * v = a; X * b = (X *)v;` It is only not guaranteed that a function pointer can be stored as `void *`, albeit that works with almost all platforms, but the C standard allows data and function pointers to have a different representation. – Mecki Dec 18 '17 at 14:31
  • @Mecki - You confuse _conversions_ with _reinterpretations_ (‘‘type punning’’). While implicit (assignment) or explicit (typecast) conversions between `void *` and `struct … *` are guaranteed to work, reading a union member other than the member last stored reinterprets the value of the stored type as of another type, maybe _a trap representation_. – Armali Jan 03 '18 at 10:45
0

The scenario you describe could realistically arise in cases where different modules each declare their own structures with a particular layout and use them to exchange data, and there is a desire to change some functions in a header file from "extern" scope to "inline" scope. Unfortunately, your scenario falls into the category of useful behaviors which compilers used to support, and which sometimes have no practical alternative, but for which support is no longer mandated by the Standard, and which some compilers can no longer support without disabling a broad range of useful optimizations in addition to the useless breaking "optimizations" allowed by the Standard.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • There's no practical case that demands a function declare a local struct type and pass the address of an instance of it to some other function – M.M May 18 '17 at 22:25
  • @M.M: Start with an outside function, perhaps written in a language other than C, which requires data in a specified format but doesn't specify a particular type name for it. Modules X, Y, and Z all define their own typedefs for that purpose, none of which happen to use structure tags. Behavior will be defined if all actions using the separately-defined structures occurs across compilation-unit boundaries. Is there any way X's header can in-line its functions while remaining compatible with Y and Z? – supercat May 18 '17 at 23:53
  • @M.M: That pattern is less common than some other important ones that C99 let compilers break, but it matches the OP's question. A more important situation which C89 compilers could handle and modern C can't is being able to have a function operate on structures which end in various sizes of array. Unless a C89 compiler's structure layout rules place different sizes of arrays differently (something that would be allowed, but few if any compilers for common platforms actually do), a function that receives a pointer to a structure whose last member is an array wouldn't need to know... – supercat May 19 '17 at 00:08
  • ...nor care about the actual size of the array so long as it knew how many elements it should use. Rather than try to define a different named structure type for every size, it was easier and more practical to use a macro to declare an anonymous structure type of whatever size happened to be needed in each particular situation. Essentially universally supported among C89 compilers for commonplace platforms, but not possible in "modern C". – supercat May 19 '17 at 00:12