Discussion:
`atomic_fetch_add` on pointer types?
Add Reply
Andrey Tarasevich
2024-12-27 22:28:03 UTC
Reply
Permalink
The code

#include <stdatomic.h>
#include <stdio.h>

int main()
{
int v[2], *_Atomic p = v;
atomic_fetch_add(&p, 1);
printf("%tu\n", (char *) p - (char *) v);
}

GCC prints 1 (https://godbolt.org/z/55Pjcnd3Y), while Clang prints 4
(https://godbolt.org/z/e4x6z85fe). Obviously, Clang performed the
"proper" pointer arithmetic, while GCC ignored the pointer type.

Which one is correct here?

7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)
1 The following operations perform arithmetic and bitwise
computations. All of these operations are applicable to an object of any
atomic integer type. None of these operations is applicable to atomic_bool.

Is this wording intended to restrict these operations to integer types only?

But later 7.17.7.5 also says
3 For address types, the result may be an undefined address, but the
operations otherwise have no undefined behavior.

However, I was unable to find any mention of "address types" anywhere
else in the standard. This is the only spot in the entire document
mentioning "address types". What types are "address types"?
--
Best regards,
Andrey
Keith Thompson
2024-12-28 01:43:40 UTC
Reply
Permalink
Post by Andrey Tarasevich
The code
#include <stdatomic.h>
#include <stdio.h>
int main()
{
int v[2], *_Atomic p = v;
atomic_fetch_add(&p, 1);
printf("%tu\n", (char *) p - (char *) v);
}
GCC prints 1 (https://godbolt.org/z/55Pjcnd3Y), while Clang prints 4
(https://godbolt.org/z/e4x6z85fe). Obviously, Clang performed the
"proper" pointer arithmetic, while GCC ignored the pointer type.
Which one is correct here?
See also the thread in comp.std.c, where I wrote that I think you've
found an error in the standard. (Probably just one newsgroup or the
other would have been more appropriate.)

IMHO neither is correct. The description clearly restricts the
operations to atomic integer types. The mention of "address types"
appears to be an error.

Perhaps the intent was to allow just _add and _sub on atomic pointer
types, but the standard doesn't express that intent. If the intent
is to allow those operations on pointers, it seems clear that clang's
interpretation would be correct; pointer arithmetic counts elements,
not bytes.

Note that if you change atomic_fetch_add to _or, _and, or _xor, gcc
doesn't complain, which seems clearly incorrect. clang correctly
complains "address argument to atomic operation must be a pointer
to atomic integer", but it quietly accepts _add and _sub.

[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Chris M. Thomasson
2024-12-28 04:12:17 UTC
Reply
Permalink
Post by Andrey Tarasevich
The code
  #include <stdatomic.h>
  #include <stdio.h>
  int main()
  {
    int v[2], *_Atomic p = v;
    atomic_fetch_add(&p, 1);
    printf("%tu\n", (char *) p - (char *) v);
  }
Try making it an uintptr_t?
Post by Andrey Tarasevich
GCC prints 1 (https://godbolt.org/z/55Pjcnd3Y), while Clang prints 4
(https://godbolt.org/z/e4x6z85fe). Obviously, Clang performed the
"proper" pointer arithmetic, while GCC ignored the pointer type.
Which one is correct here?
7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)
1 The following operations perform arithmetic and bitwise
computations. All of these operations are applicable to an object of any
atomic integer type. None of these operations is applicable to atomic_bool.
Is this wording intended to restrict these operations to integer types only?
But later 7.17.7.5 also says
3 For address types, the result may be an undefined address, but the
operations otherwise have no undefined behavior.
However, I was unable to find any mention of "address types" anywhere
else in the standard. This is the only spot in the entire document
mentioning "address types". What types are "address types"?
Tim Rentsch
2024-12-31 14:08:31 UTC
Reply
Permalink
Andrey Tarasevich <***@hotmail.com> writes:

[some whitespace in quoted text was modified]
Post by Andrey Tarasevich
The code
#include <stdatomic.h>
#include <stdio.h>
int main()
{
int v[2], *_Atomic p = v;
atomic_fetch_add(&p, 1);
printf("%tu\n", (char *) p - (char *) v);
}
GCC prints 1 (https://godbolt.org/z/55Pjcnd3Y), while Clang prints 4
(https://godbolt.org/z/e4x6z85fe). Obviously, Clang performed the
"proper" pointer arithmetic, while GCC ignored the pointer type.
Which one is correct here?
The behavior shown by clang is obviously the more sensible choice.
The C standard is not as clear on this point as I would like it to
be, but I believe the behavior shown by clang is what was intended.
Post by Andrey Tarasevich
7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)
1 The following operations perform arithmetic and bitwise
computations. All of these operations are applicable to an
object of any atomic integer type. None of these operations
is applicable to atomic_bool.
Is this wording intended to restrict these operations to integer types only?
I believe it was not; otherwise there is no point to the paragraph
you mention next. See also below.
Post by Andrey Tarasevich
But later 7.17.7.5 also says
3 For address types, the result may be an undefined address, but
the operations otherwise have no undefined behavior.
However, I was unable to find any mention of "address types" anywhere
else in the standard. This is the only spot in the entire document
mentioning "address types". What types are "address types"?
Surely "address types" should be taken as being synonymous with
"pointer types". More details to follow in comp.std.c.

Loading...