2

Considering this code, VC9 doesn't detect aliasing :

typedef struct { int x, y; } vec_t;

void rotate_cw(vec_t const *from,
               vec_t       *to)
{
        /* Notice x depends on y and vice versa */
        to->x = from->y;
        to->y = -from->x;
}

/* ... */
vec_t a, b;
rotate_cw(&a, &b); /* OK, no aliasing */
rotate_cw(&a, &a); /* FAIL, aliasing is not detected */

The obvious fix is to use a temporary :

void rotate_cw(vec_t const *from,
               vec_t       *to)
{
        int temp = from->x;
        to->x = from->y;
        to->y = -temp;
}

Is this standard behavior ? I was expecting that the compiler, unless told so, would assume both pointers to be possibly aliased.

Mat
  • 202,337
  • 40
  • 393
  • 406
diapir
  • 2,872
  • 1
  • 19
  • 26
  • 4
    Yep, this is not standard behavior - looks like a compiler bug, at least in C99 and C++. They are explicitly allowed to alias each other. I don't know how the matter was in C89, which seems to be what you are for :( But i think i read in C89, things were even more permissible – Johannes Schaub - litb Jun 07 '09 at 20:04
  • You're expecting c to take care of a corner case for you? It doesn't do that: you're expect to worry about these kind of details for yourself. That might be a reason to consider a higher level language, but it is *not* a bug in c: the compiler does exactly what you tell it to. – dmckee --- ex-moderator kitten Jun 07 '09 at 20:24
  • @dmckee: To be fair, the fixed version came first and I like my macro-assembler just fine ;) – diapir Jun 07 '09 at 20:40
  • @diapir: Sorry. I didn't mean to be derisive. Just to point out that c is a pretty low level language. The '99 standard added some stuff for smart compilers, but the traditional language is pretty primitive that way. Cheers. – dmckee --- ex-moderator kitten Jun 07 '09 at 20:43
  • 3
    The compiler does assume the pointers to be possibly aliases. However that just means that it won't do things like re-order the assignments, if the possible aliasing could cause that to fail. It is not going to second-guess your code and try to figure out what you meant to do. – mark4o Jun 07 '09 at 20:52
  • 1
    the compiler doesn't have to guess. it just has to issue a real load from memory. and it *has* to do that, since the pointers may alias. Doing a real load hasn't got much to do with being a high level or a low level language. Of course that is not a bug in C - but in his compiler, if the compiler optimizes stuff the wrong way (too aggressively). Try adding "volatile" in addition to "const" and see what happens – Johannes Schaub - litb Jun 07 '09 at 21:26
  • No, the compiler will assume that you meant to do exactly what your program says. That is, if from and to are equal, x will equal from->y and y will equal the negated value of that, just like it says. The program is valid and the compiler must produce a program that produces that result. – mark4o Jun 07 '09 at 21:27
  • mark4o, what do you find in my comment that contradicts your "the compiler will assume that you meant to do exactly what your program says" that makes you say "No" ? Incidentally, what you describe is exactly what me and diapir talk about. But his compiler does *NOT* do that, if i understand diapir right. His compiler does *NOT* detect that aliasing, and assigns some wrong value. – Johannes Schaub - litb Jun 07 '09 at 21:34
  • For that reason i don't understand why he is introducing that temporary variable as a "fix", because that effectively says he doesn't want his argument to be aliased. Thus, what he wants is "restrict", and not "norestrict". – Johannes Schaub - litb Jun 07 '09 at 21:37
  • 1
    Hmm i think i see now. He seems to think "aliasing" means that two pointers do *not* point to the same object. But aliasing means the opposite, of course. That may explain the confusion among us :) – Johannes Schaub - litb Jun 07 '09 at 21:45
  • @litb Sorry, I think we are in agreement. The OP seems to think that the compiler is not detecting possible aliasing simply because it did not produce the same output as the "fix". – mark4o Jun 07 '09 at 22:05

3 Answers3

4

Check out this answer.

Try putting __restrict before the parameters, seems to be the only way anybody found of getting MSVC to give any warnings.

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Thanks for the link. I'd rather need a __norestrict keyword so the compiler doesn't assume restrict-edness. – diapir Jun 07 '09 at 20:27
4

The code as written is perfectly valid, in C89 or C99. It is obscure, but there is nothing for the compiler to diagnose, so it doesn't diagnose.

If you used C99 and 'restrict' on both parameters of the function, then you would get an error - if your compiler supports C99. AFAIK, no current version of MSVC yet supports C99 fully.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

Before C99 invented the restrict qualifier, some C compilers included optimization options which would direct them to make certain assumptions about pointer usage; the manuals I've seen for such compilers expressly warned that such optimizations were not standards-compliant, and may arbitrarily cause code using certain particular constructs whose behavior was defined by the Standard to behave in a manner which was contrary to both the Standard and programmer intention. From the point of view of the manual, the optimizations told the compiler to compile a subset of C which did not define the behavior of certain corner cases that were defined in C, but which would allow the generation of more efficient code for those cases it did define.

supercat
  • 77,689
  • 9
  • 166
  • 211