Why can't we declare a variable of type void?

后端 未结 7 1601
盖世英雄少女心
盖世英雄少女心 2020-12-08 09:43

I\'m looking for a formal explanation of that fact in the Standard. I\'ve found what 3.9.1/9 says and trying to give an explanation used that section.

S

相关标签:
7条回答
  • 2020-12-08 10:14

    void is an incomplete type - you can only declare pointers to them and use them in function signatures. Obviously, extern Foo f; is permitted because struct Foo can be defined in another compilation unit (and if it's not the error will be detected by the linker), but void can't ever be "defined" (and the compiler knows this, of course) so void's quite special in this case.

    0 讨论(0)
  • 2020-12-08 10:19

    Well - I really don't see the rationale behind this. It's going to be great if this way we can declare a variable with unknown type. Something like 'void *' and arrays of unknown size. Imagine code like this:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    extern void f;
    
    int main()
    {
        cout << (int &)f << endl; //cout 'f' as it was integer
    }
    
    struct {
        int a;
        double b;
    } f{};
    

    You can now actually do something similar with arrays:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    struct Foo;
    
    extern int arr[];
    
    int main()
    {
        cout << arr[2] << endl;
    }
    
    int arr[4]{};
    

    Life example.

    0 讨论(0)
  • 2020-12-08 10:27

    You cannot declare a variable of type void because variables must have object type or be references, extern void f; doesn't declare a reference, and void is not an object type:

    Section 3 [basic] says that

    A variable is introduced by the declaration of a reference other than a non-static data member or of an object.

    Section 3.9 [basic.types] says that

    An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not a void type.

    0 讨论(0)
  • 2020-12-08 10:28

    If the variable has an empty set of values, it can't be used for anything.

    You can't assign to it, because there are no possible values to assign.

    You can't access it, because you never assigned to it, so it has an indeterminate value.

    Since there are no possible values, there's no size of the variable.

    void is just used as a placeholder in variable places. It's used as a return type to indicate that the function doesn't return a value. It's used in C in the argument list to indicate that the function takes no arguments (to resolve an ambiguity from the pre-prototype version of the language). And it's used with pointer declarations to create generic pointers that can be translated to any other pointer type. There's no such analogous use for it in variable declarations.

    0 讨论(0)
  • 2020-12-08 10:33

    Because C and C++ assume that any objects may be compared for identity by comparing their addresses, they must ensure that all objects have fixed non-zero size. Were it not for that requirement, there are in fact many cases where it would be somewhat useful to declare zero-sized objects [e.g. in code which uses templates which contain fields that will sometimes be useful and sometimes not, or as a means of forcing a structure to be padded to a certain alignment requiring that it contain an element requiring such alignment]. As it is, however, zero-size types would be inconsistent with fact that the rule specifying that every object has a unique address includes no exception which would allow for the existence of zero-sized objects that could share an address.

    Even if zero-size objects were permissible, however, a "pointer to unknown object" should not be the same as a "pointer to a zero-size object". Given that the type void* is used for the former, that would imply that something else should be used for the latter, which would in turn imply that something other than void should be the type of thing to which a zero-sized object points.

    0 讨论(0)
  • 2020-12-08 10:34

    [edit] The answer below makes valid observations, but they're contradicting. As these might be valuable, I'll not delete them, but see Ben Voight's answer and the comments there for a more straightforward approach.

    Your observations about extern declarations are specifically allowed by 7.1.1/8:

    The name of a declared but undefined class can be used in an extern declaration. Such a declaration can only be used in ways that do not require a complete class type.

    void is not a "declared but undefined class", and there's no other exception in 7.1.1 which applies.

    Additionally, 3.9/5 is fairly explicit that it is in fact allowed:

    A class that has been declared but not defined, an enumeration type in certain contexts (7.2), or an array of unknown size or of incomplete element type, is an incompletely-defined object type. [45] Incompletely defined object types and the void types are incomplete types (3.9.1). Objects shall not be defined to have an incomplete type.

    Emphasis mine. This part of the standard is quite specific about the differences between definitions and declarations, so by omission it specifies that declarations are allowed.

    0 讨论(0)
提交回复
热议问题