{"id":4016,"date":"2019-01-13T11:35:31","date_gmt":"2019-01-13T10:35:31","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=4016"},"modified":"2019-01-13T14:02:23","modified_gmt":"2019-01-13T13:02:23","slug":"c-guns-not-another-level-of-indirection","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=4016","title":{"rendered":"C++ Guns: NOT another level of indirection"},"content":{"rendered":"<p>The following code snips does NOT create a level of indirection. You can see it by introspect the assembler code.<br \/>\nSo don't worry, start structure your data. See the <a href=\"http:\/\/roboblog.fatal-fury.de\/?p=4024\">next post<\/a> for a practice example.<\/p>\n<h3>Example 1<\/h3>\n<p>Lets begin with a simple struct contains 3 members: double, float, int. Sum them up. And see what the compile generate<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct A {\r\n    double d;\r\n    float f;\r\n    int i;\r\n};\r\n\r\nstatic_assert(sizeof(A) == 16);\r\n\r\nauto func(const A&amp; a){\r\n    return a.d + a.f + a.i;\r\n}\r\n<\/pre>\n<p>With the static assert sizeof you can be sure there is no padding in the data structure. The generate ASM code compiled with GCC 8.1 -O1 I comment it to make it easier for you. <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfunc(A const&amp;):\r\n        pxor    %xmm0, %xmm0              # xmm0 = 0\r\n        cvtss2sd        8(%rdi), %xmm0    # convert float to double and store it in xmm0\r\n        addsd   (%rdi), %xmm0             # add double and the converted float to xmm0\r\n        pxor    %xmm1, %xmm1              # xmm1 = 0\r\n        cvtsi2sd        12(%rdi), %xmm1   # convert integer to double and store it in xmm1\r\n        addsd   %xmm1, %xmm0              # add the already added float+double to the converted integer to xmm0\r\n        ret                               # return xmm0 as result\r\n<\/pre>\n<p>You can see two conversions from int\/float to double and two additions. You can also see the offsets. The double value has offset 0, the float value 8 bytes and the integer value (8+4)=12 bytes. This is quite straight. So add more code.<\/p>\n<h3>Example 2<\/h3>\n<p>This example create a nested struct Bdata inside struct B. Sum the values up again and see what the compiler generate.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct B {\r\n    struct Bdata {\r\n        double d;\r\n        float f;\r\n        int i;\r\n    };\r\n\r\n    Bdata b;\r\n};\r\n\r\nstatic_assert(sizeof(B) == 16);\r\n\r\nauto func2(const B&amp; a){\r\n    return a.b.d + a.b.f + a.b.i;\r\n}\r\n<\/pre>\n<p>It is exactly, 100%, the same assembler code as example1 ! So i don't show it here again. The memory layout of struct B is the same as struct A, so the same ASM code is generated. No overhead by the extra variable <em>b<\/em>.<\/p>\n<h3>Example 3<\/h3>\n<p>In the next example a std::tuple is used to store the 3 values. The access is provided with the function std::get. It looks different. But wait...<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct C {\r\n    std::tuple&lt;double, float, int&gt; c;\r\n};\r\n\r\nstatic_assert(sizeof(C) == 16);\r\n\r\nauto func3(const C&amp; a){\r\n    return std::get&lt;0&gt;(a.c) + std::get&lt;1&gt;(a.c) + std::get&lt;2&gt;(a.c);\r\n}\r\n<\/pre>\n<p>This time, the generated code is different<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfunc3(C const&amp;):\r\n        pxor    %xmm0, %xmm0             # xmm0 = 0\r\n        cvtss2sd        4(%rdi), %xmm0   # convert float to double and store it in xmm0\r\n        addsd   8(%rdi), %xmm0           # add double and the converted float to xmm0\r\n        pxor    %xmm1, %xmm1             # xmm1 = 0\r\n        cvtsi2sd        (%rdi), %xmm1    # convert integer to double and store it in xmm1\r\n        addsd   %xmm1, %xmm0             # add the already added float+double to the converted integer to xmm0\r\n        ret                              # return xmm0 as result\r\n<\/pre>\n<p>But if you take a closer look, it is still the same! Only the memory layout has changed. First the integer, then the float, then the double. A std::stuple store it's values in reverse order! But the generated assembler code is 100% identical to the first example!<\/p>\n<h3>Example 4<\/h3>\n<p>In the last example I change the structure a little bit. But you can guess, the result is still the same.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct D {\r\n    double d;\r\n\r\n    struct Ddata {    \r\n        float f;\r\n        int i;\r\n    };\r\n\r\n    Ddata x;\r\n};\r\n\r\nstatic_assert(sizeof(D) == 16);\r\n\r\nauto func4(const D&amp; a){\r\n    return a.d + a.x.f + a.x.i;\r\n}\r\n<\/pre>\n<p>See the <a href=\"http:\/\/roboblog.fatal-fury.de\/?p=4024\">next post<\/a> for a practice example.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The following code snips does NOT create a level of indirection. You can see it by introspect the assembler code. So don't worry, start structure your data. See the next post for a practice example. Example 1 Lets begin with a simple struct contains 3 members: double, float, int. Sum them up. And see what [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-4016","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4016","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4016"}],"version-history":[{"count":9,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4016\/revisions"}],"predecessor-version":[{"id":4033,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4016\/revisions\/4033"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4016"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4016"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4016"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}