3

http://c0x.coding-guidelines.com/6.7.2.1.html:

1401 If the struct-declaration-list contains no named members, the behavior is undefined.

Does this mean that the following is illegal?

struct C { };

Or what does it mean?

I used a Convention=>C Ada pointer to an empty struct (in fact empty Ada record) to serve instead void* in my bindings of a C library (because there is no void* in Ada). I wonder if this is incorrect.

What do I misunderstand?


See also "Do not pass or return structs with no fields of non-zero size to extern (C) functions. According to C11 6.7.2.1p8 this is undefined behavior." at https://dlang.org/spec/struct.html

porton
  • 5,214
  • 11
  • 47
  • 95
  • `struct C{ };` doesn't even match the standardized syntax. `struct C { _Static_assert(1,""); };` would (`_Static_assert` are unnecessary ugliness) but for that you have UB if there aren't any _named_ members inside the struc (http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p8). – Petr Skocik Jan 04 '19 at 17:27

2 Answers2

6

Very little in C is illegal, meaning you cannot do it. Rather, many things are not defined by the C standard, meaning that, if you do them, the C standard does not say what will happen. Structures with no named members are such a thing.

C 2018 6.7.2.1 8 says, in part:

If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined.

If you need something to serve as an “unknown type” and do not want to use void, then you can declare a structure whose tag is known but whose contents are not, as with:

struct foo;

Then you can use pointers to such structures (for example, you can define a pointer struct foo *p;), but the compiler will not know the size or contents of such structures, so it cannot help you allocate them, manage arrays of them, or otherwise use them other than by passing pointers around and asking external routines (which do know about the contents).

Normally, in operations between C routines in one module and C routines in another module:

  • In one source module that did not know about the contents of the structure, you would use a pointer (struct foo *).
  • Another source module (often a software library of some sort) would know about the contents of the structure. It would, inside its own source code, define the full structure with struct foo { /* various things */ };, and it would perform services on this structure for the first module.
  • Between two such C modules, the rules of the C standard would define the behavior.

Since you are interfacing between C and Ada, the rules for those interactions must be provided by your C and Ada implementations.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Hm, well, why they say that `sizeof(struct C)==1` for `struct C { };`, if it is not defined at all? – porton Dec 27 '18 at 23:53
  • 2
    @porton: Who is “they”? I presume you are asking about the page at [one of your links](https://dlang.org/spec/struct.html). it says something about g++ and clang++ producing 1 for `sizeof`. Recall that very little is illegal in C. Compilers are allowed to extend the language. Since the C standard does not define what happens with an empty structure, a compiler can define what happens—as long as you are using that compiler. – Eric Postpischil Dec 27 '18 at 23:59
  • @porton • `struct C { };` does not mean "it is not defined at all", it means that it _is_ defined. `struct C;` is declared but not defined, which is why `struct foo* ptr;` works. An empty struct has a non-zero size because to have an address needs a non-zero size; think of it as padding byte(s) and/or alignment byte(s). – Eljay May 14 '20 at 15:11
1

From the point of view of writing an Ada binding to a C library, it doesn't matter what your Ada Convention-C access type to use for void* designates. You're never going to do anything with objects of the type except pass them to imported C functions. I usually use

type Void_Ptr is access all Integer;
pragma Convention (C, Void_Ptr);
Jeffrey R. Carter
  • 3,033
  • 9
  • 10
  • I think you are wrong. Align of Integer and of structs may be different – porton Jan 05 '19 at 07:38
  • The alignments of various types is irrelevant to the definition of `void*`. – Jeffrey R. Carter Jan 05 '19 at 10:09
  • I tried the alignments of various types using `void*`, but to dereference it, it needs a lot of casting. So now I'm thinking of using empty struct and fill it with `malloc`, is that possible ? – R1S8K Aug 26 '21 at 18:57
  • If you are allocating or dereferencing a `void*` from a binding to a C library in Ada, then you are doing something wrong. – Jeffrey R. Carter Sep 13 '21 at 08:04