Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it invalid for a union type declared in one function to be used in another function?

When I read ISO/IEC 9899:1999 (see:6.5.2.3), I saw an example like this (emphasis mine) :

The following is not a valid fragment (because the union type is not visible within function f):

struct t1 { int m; }; struct t2 { int m; }; int f(struct t1 * p1, struct t2 * p2) {       if (p1->m < 0)             p2->m = -p2->m;       return p1->m; } int g() {       union {             struct t1 s1;             struct t2 s2;       } u;       /* ... */       return f(&u.s1, &u.s2); } 

I found no errors and warnings when I tested.

My question is: Why is this fragment invalid?

like image 674
kangjianwei Avatar asked Sep 26 '18 07:09

kangjianwei


People also ask

Can unions have functions?

A union can have member functions (including constructors and destructors), but not virtual functions. A union cannot have base classes and cannot be used as a base class.

What is union declaration?

A "union declaration" specifies a set of variable values and, optionally, a tag naming the union. The variable values are called "members" of the union and can have different types. Unions are similar to "variant records" in other languages.

When would one use a union type in TypeScript?

In TypeScript, a union type variable is a variable which can store multiple type of values (i.e. number, string etc). A union type allows us to define a variable with multiple types. The union type variables are defined using the pipe ( '|' ) symbol between the types.

How do you handle a union type in TypeScript?

TypeScript Union Type Narrowing To narrow a variable to a specific type, implement a type guard. Use the typeof operator with the variable name and compare it with the type you expect for the variable.


1 Answers

The example attempts to illustrate the paragraph beforehand1 (emphasis mine):

6.5.2.3 ¶6

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

Since f is declared before g, and furthermore the unnamed union type is local to g, there is no questioning the union type isn't visible in f.

The example doesn't show how u is initialized, but assuming the last written to member is u.s2.m, the function has undefined behavior because it inspects p1->m without the common initial sequence guarantee being in effect.

Same goes the other way, if it's u.s1.m that was last written to before the function call, than accessing p2->m is undefined behavior.

Note that f itself is not invalid. It's a perfectly reasonable function definition. The undefined behavior stems from passing into it &u.s1 and &u.s2 as arguments. That is what's causing undefined behavior.


1 - I'm quoting n1570, the C11 standard draft. But the specification should be the same, subject only to moving a paragraph or two up/down.

like image 161
StoryTeller - Unslander Monica Avatar answered Oct 22 '22 03:10

StoryTeller - Unslander Monica