How to resolve pointer alias issues?

后端 未结 2 2032
孤城傲影
孤城傲影 2021-01-22 14:18

Careless use of templates can cause bloat. One way to avoid that bloat is to have a thin typesafe template that wraps non-typesafe non-template code. To do this, the wrapper nee

相关标签:
2条回答
  • 2021-01-22 14:44

    Careless use of templates CAN cause bloat. But you're totally missing the point here.

    • Templates cause bloat when used carelessly, not carefully.
    • The quantity of runtime errors avoided by templates is massive.
    • The speed of templated code is far greater than non-templated code.
    • The size of the executable is absolutely trivial unless you run on an embedded system.
    • The STL provides a map container (which is a binary search tree) for your use.

    You just haven't thought this through properly at all. The advantages templates offer far outweigh a few kb in executable size.

    It's also worth noting that the code works as expected on Visual Studio 2010.

    0 讨论(0)
  • 2021-01-22 14:46

    Did you switch off warnings? You should have got some "dereferencing type punned pointers violates strict aliasing", because thats exactly what you do at (void**) Ptr_Add(...

    The compiler is free to assume that pointers to different types do not alias (with a few execpitions), and will produce optimized code which caches the targets of pointers in registers. To avoid that, you have to use unions to convert between different pointers types. Quoting from http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options:

    In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int, but not a void* or a double. A character type may alias any other type.

    Pay special attention to code like this:

         union a_union {
            int i;
            double d;
          };
    
         int f() {
            union a_union t;
            t.d = 3.0;
            return t.i;
          }
    

    The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above will work as expected. See Structures unions enumerations and bit-fields implementation. However, this code might not:

         int f() {
            union a_union t;
            int* ip;
            t.d = 3.0;
            ip = &t.i;
            return *ip;
          }
    

    Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:

         int f() {
            double d = 3.0;
            return ((union a_union *) &d)->i;
          }
    

    The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os.

    In your case you could use something like

    union {
        void** ret_ptr;
        ptrdiff_t in_ptr;
    }
    

    but the code in ptr_add just looks horrible ;-)

    Or just disable this specific optimization with "fno-strict-aliasing". Better fix your code though ;-)

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