Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There was a proposal for a unit type for C++, it would be a zero-sized type just like void except that you could actually use it to declare a variable and pass around as a value, like other regular types.

The less serious proposal: have it be `long void`



Empty structs are supported in clang; I think it's a GCC extension to C. This program:

  #include <stdio.h>
  
  typedef struct {} unit;
  
  static unit f(unit *p)
  {
      return (unit){};
  }
  
  static void g(unit u)
  {
  }
  
  int main()
  {
      unit a = {}, b = {};
      a = b;
      f(&a);
      g(b);
      printf("a is at %lx, b is at %lx, "
              "sizeof unit is %d\n",
              (unsigned long)&a, (unsigned long)&b,
              (int)sizeof(unit));
      return 0;
  }
compiles without complaints on my cellphone and produces the output:

a is at 7ffb39805b, b is at 7ffb39805a, sizeof unit is 0

So you can declare empty structs as variables, return them, assign them, pass them as parameters, take their addresses, create them in struct literals, and dereference pointers to them. clang is assigning different addresses to different empty-struct local variables, but presumably in an array all of them would have the same address, unlike in C++.

I wouldn't be confident that you could malloc them, and I wouldn't be surprised if passing them by value uncovered compiler divergences in the interpretation of the ABI. (I spent most of last night tracking down a bug due to LuaJIT/GCC ABI differences in the implementation of parameter passing.)


> Empty structs are supported in clang; I think it's a GCC extension to C.

Indeed. See https://gcc.gnu.org/onlinedocs/gcc-15.2.0/gcc/Empty-Structur....

That page also says “In C++, empty structures are part of the language”, and “G++ treats empty structures as if they had a single member of type char”. I think that means the size of empty structs differs between GCC C and GCC C++.


Thanks! Yes, C++ requires all objects to have a nonzero size.

In GCC these two variables get the same address; also true in clang with -O.


Why couldn't you malloc them? Malloc doesn't care about types, it just wants the number of bytes, and 0 is a perfectly valid value to pass to malloc. Now, it's unspecified whether malloc will give you back a pointer distinct from all other non-freed allocated blocks or NULL, but if you don't rely on address as identity that is irrelevant.


You're right, in the standard it's implementation-defined. I mistakenly thought malloc(0) was undefined. That said, it's probably not the best-tested code path in the system library.


And correspondingly calling free() on the returned value is also unlikely to be particularly well tested.


Well, unless it's NULL. I'm pretty sure that people call free(0) a lot.


I mean, these are literally all special values that are explicitly called out in all the relevant standards (both ISO C and POSIX). Anyone who is competent and is writing tests for libc would surely cover that.


Probably malloc(0) is not completely untested, yes. But it's unlikely to be regularly executed by applications.


In Delphi, and possibly other Pascal variants, you can do this with a type that's just an empty record (struct). It'll have zero size, but you can declare variables of that type, pass it as parameters and such.

IIRC things get a bit funky using this in certain situations, so I'm not sure the compiler devs actually considered this or if it's just a happy accident of sorts.


The problem is that it's still a nominal type system, so each empty struct is still a different type. A proper unit type has a single value of that type, and it's the same throughout the entire program.


> The problem is that it's still a nominal type system, so each empty struct is still a different type.

Fair point, though for me that was a feature when I used it in Delphi. Allowed me to differentiate them when using them as type parameters (generics).


This would be useful for decoding ASN.1 CHOICEs and open types that contain a NULL option. These should compile to a sum type where the components have values, except that the NULL cases should not.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: