Can a char array be used with any data type?

佐手、 提交于 2019-11-30 09:40:11

The declared type of the static object Array is char. The effective type of this object is it's declared type. The effective type of a static object cannot be changed, thus for the remainder of the program the effective type of Array is char.

If you try to access the value of an object with a type that is not compatible with, or not on this list1, the behavior is undefined.

Your code tries to access the stored value of Array using the type int. This type is not compatible with the type char and is not on the list of exceptions, so the behavior is undefined when you read the array using the int pointer p:

printf("%d ", p[n]);

1 (Quoted from: ISO:IEC 9899:201X 6.5 Expressions 7 )
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

No you cannot use an arbitrary byte array for an arbitrary type because of possible alignment problems. The standard says in 6.3.2.3 Conversions/Pointers (emphasize mine):

A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

As a char as the smallest alignment requirement, you cannot make sure that your char array will be correctly aligned for any other type. That is why malloc guarantees that a buffer obtained by malloc (even if it is a void *) has the largest possible alignement requirement to be able to accept any other type.


I think that

union {
    char buf[128];
    long long i;
    void * p;
    long double f;
};

should have correct alignment for any type as it is compatible with largest basic types (as defined in 6.2.5 Types). I am pretty sure that it will work for all common implementations (gcc, clang, msvc, ...) but unfortunately I could not find any confirmation that the standard allows it. Essentially because of the strict aliasing rule as defined in 6.5 Expression §7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type.

So IMHO there is not portable and standard conformant way to build a custom allocator not using malloc.

If one reads the rationale of the C89 Standard, the only reason that the type- aliasing rules exist is to avoid requiring compilers to make "worst-case aliasing assumptions". The given example was:

    int a;
    void f( double * b )
    {
        a = 1;
        *b = 2.0;
        g(a);
    }

If program creates a "char" array within a union containing something whose alignment would be suitable for any type, takes the address thereof, and never accesses the storage of that structure except through the resulting pointer, there should be no reason why aliasing rules should cause any difficulty.

It's worthwhile to note that the authors of the Standard recognized that an implementation could be simultaneously compliant but useless; see the rationale for C89 2.2.4.1:

While a deficient implementation could probably contrive a program that meets this requirement, yet still succeed in being useless, the Committee felt that such ingenuity would probably require more work than making something useful. The sense of the Committee is that implementors should not construe the translation limits as the values of hard-wired parameters, but rather as a set of criteria by which an implementation will be judged.

While that particular statement is made with regard to implementation limits, the only way to interpret the C89 as being even remotely compatible with the C dialects that preceded it is to regard it as applying more broadly as well: the Standard doesn't try to exhaustively specify everything that a program should be able to do, but relies upon compiler writers' exercising some common sense.

Use of a character-type array as a backing store of any type, assuming one ensures alignment issues are taken care of, shouldn't cause any problems with a non-obtusely written compiler. The Standard didn't mandate that compiler writers allow such things because they saw no reason to expect them to do otherwise. Unfortunately, they failed to foresee the path the language would take in the 21st Century.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!