Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes the compiler, as said by Wallyk, is able to remove useless operations in this case. </p> <p>However you must remember that when you specify a function signature something is lost in the translation from your problem domain to C. Consider the following function:</p> <pre><code>void transform(const double *xyz, // Source point double *txyz, // Transformed points const double *m, // 4x3 transformation matrix int n) // Number of points to transform { for (int i=0; i&lt;n; i++) { txyz[0] = xyz[0]*m[0] + xyz[1]*m[3] + xyz[2]*m[6] + m[9]; txyz[1] = xyz[0]*m[1] + xyz[1]*m[4] + xyz[2]*m[7] + m[10]; txyz[2] = xyz[0]*m[2] + xyz[1]*m[5] + xyz[2]*m[8] + m[11]; txyz += 3; xyz += 3; } } </code></pre> <p>I think that the intent is clear, however the compiler must be paranoid and consider that the generated code must behave exactly as described by the C semantic even in cases that are of course not part of the original problem of transforming an array of points like:</p> <ul> <li><code>txyz</code> and <code>xyz</code> are point to the same memory address, or may be they are pointing to adjacent doubles in memory</li> <li><code>m</code> is pointing inside the <code>txyz</code> area</li> </ul> <p>This means that for the above function the C compiler is forced to assume that after each write to <code>txyz</code> any of <code>xyz</code> or <code>m</code> could change and so those values cannot be loaded in free order. The resulting code consequently will not be able to take advantage of parallel execution for example of the computations of the tree coordinates even if the CPU would allow to do so.</p> <p>This case of aliasing was so common that C99 introduced a specific keyword to be able to tell the compiler that nothing that strange was intended. Putting the <code>restict</code> keyword in the declaration of <code>txyz</code> and <code>mat</code> reassures the compiler that the pointed-to memory is not accessible using other ways and the compiler is then allowed to generate better code.</p> <p>However this "paranoic" behavior is still necessary for all operations to ensure correctness and so for example if you write code like</p> <pre><code> char *s = malloc(...); char *t = malloc(...); ... use s and t ... </code></pre> <p>the compiler has no way to know that the two memory areas will be non-overlapping or, to say it better, there is no way to define a signature in the C language to express the concept that returned values from <code>malloc</code> are "non overlapping". This means that the paranoid compiler will think in the subsequent code any write to something pointed by <code>s</code> will possibily overwrite data pointed by <code>t</code> (even when you're not getting past the size passed to <code>malloc</code> I mean ;-) ).</p> <p>In your example case even a paranoid compiler is allowed to assume that</p> <ol> <li>no one will know the address of a local variable unless getting it as a parameter</li> <li>no unknown external code is executed between the reading and computation of addition</li> </ol> <p>if both those points are lost then the compiler must think to strange possibilities; for example</p> <pre><code>int a = malloc(sizeof(int)); *a = 1; printf("Hello, world.\n"); // Here *a could have been changed </code></pre> <p>This crazy thought is necessary because <code>malloc</code> knows the address of <code>a</code>; so it could have passed this information to <code>printf</code> that after printing the string could use that address to change the content of the location. This seems clearly absurd and may be the library function declaration could contain some special unportable trick, but it's necessary for correctness in general (imagine <code>malloc</code> and <code>printf</code> being two user defined functions instead of library ones).</p> <p>What does all this blurb mean? That yes, in your case the compiler is allowed to optimize, but it's very easy to remove this possibility; for example</p> <pre><code>inline int Func1 (int* a) { printf("pointed value is %i\n", *a); return *a + 1; } int main () { int v = GetIntFromUserInput(); // Assume input value is non-determinable. printf("Address of v is %p\n", &amp;v); return Func1(&amp;v); } </code></pre> <p>is a simple variation of your code, but in this case the compiler cannot avoid assuming that the second <code>printf</code> call could have changed the pointed memory even if it's passed just the pointed value and not the address (because the first call to <code>printf</code> was passed the address and so the compiler must assume that potentially that function could have stored the address to use it later to alter the variable).</p> <p>A very common misconception in C and C++ is that liberal use of the keyword <code>const</code> with pointers or (in C++) references will help the optimizer generating better code. This is completely false:</p> <ol> <li>In the declaration <code>const char *s</code> the nothing is said about that the pointed character is going to be constant; it's simply said that it is an error to change the pointed character <strong>using that pointer</strong>. In other words <code>const</code> in this case simply means that the pointer is "readonly" but doesn't tell that, for example, other pointers could be used to changed the very same memory pointed to by <code>s</code>.</li> <li>It is legal in C (and C++) to "cast away" const-ness from a pointer (or reference) to constant. So the paranoid compiler must assume that even a function has been only handed a <code>const int *</code> the function could store that pointer and later can use it to change the memory pointed to.</li> </ol> <p>The <code>const</code> keyword with pointers (and C++ references) is only meant as an aid for the programmer to avoid unintentional writing use of a pointer that was thought as being used only for reading. Once this check is performed then this <code>const</code> keyword is simply forgotten by the optimizer because it has no implications in the semantic of the language.</p> <p>Sometimes you may find another silly use of the <code>const</code> keyword with parameters that tells that the value of the parameter cannot be changed; for example <code>void foo(const int x)</code>. This kind of use has no real philosophical meaning for the signature and simply puts some little annoyance on the implementation of the called function: a parameter is a copy of a value and caller shouldn't care if the called function is going to change that copy or not... the called function can still make a copy of the parameter and change that copy so nothing is gained anyway.</p> <p>To recap... when the compiler sees</p> <pre><code>void foo(const int * const x); </code></pre> <p>must still assume that foo will potentially store away a copy of the passed pointer and that can use this copy to change the memory pointed to by <code>x</code> immediately or later when you call any other unknown function.</p> <p>This level of paranoia is required because of how the language semantic is defined.</p> <p>It is very important to understand this "aliasing" problem (there can be different ways to alter the same writable area of memory), especially with C++ where there is a common anti-pattern of passing around const references instead of values even when logically the function should accept a value. See <a href="https://stackoverflow.com/questions/4705593/int-vs-const-int/4705871#4705871">this answer</a> if you are also using C++.</p> <p>All these are the reasons for which when dealing with pointers or references the optimizer has much less freedom than with local copies.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload