Saturday, June 19, 2021

Digest for comp.lang.c++@googlegroups.com - 25 updates in 2 topics

David Brown <david.brown@hesbynett.no>: Jun 16 02:43PM +0200


> Hand up. What does it do? Or is it simply the same as static int because
> the compiler doesn't care about certain syntax order, the same way that a[0]
> and 0[a] are equivalent?
 
"void bar(int a[static 10]);" means "bar" can only be called with a
pointer to an array of at least 10 int's. The compiler can optimise the
implementation based on that, or warn if the function is called in a way
that violates this (for example, with a null pointer).
 
It's a fairly obscure usage, and I think few C programmers will know
about it even if they have long experience of the language. I can't say
it is a feature I have ever thought to use. You could use:
 
void foo(int a[static 1]);
 
as a portable alternative to gcc's
 
void foo(int * a) __attribute__((nonull));
 
However, I would say that gcc's syntax is a lot clearer (assuming, of
course, you are using a compiler that accepts it).
David Brown <david.brown@hesbynett.no>: Jun 16 02:44PM +0200

On 16/06/2021 14:43, David Brown wrote:
 
> void foo(int * a) __attribute__((nonull));
 
> However, I would say that gcc's syntax is a lot clearer (assuming, of
> course, you are using a compiler that accepts it).
 
I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does
not exist for C++.
Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:14PM

> "static" in "void bar(int a[static 10]);" is doing?), people will find
> unusual ways to express things. And it is best solved by reading each
> other's code, talking together, and sharing information.
 
C (and thus usually also C++) can indeed have some weird features that
aren't widely known even by experienced programmers. For example, I would
bet that quite a large portion of C (and C++) programmers would think
this is invalid and doesn't compile:
 
int i = 3;
int j = i["hello"];
Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:16PM

> You have lost capability to read, Juha, so you build straw-men that I did not
> write about C++98 and so then argue with those.
 
Is it even possible to just have a conversation in this newsgroup without
accusations being thrown around? Just relax.
Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:09PM

> presuming that nothing else happens. However, it is unspecified when this
> joyous event occurs and is observable by a given execution thread. That
> requires sequencing.
 
A variable being atomic guarantees that no thread will see a garbage value
for it. In other words, if one thread is changing the value of the atomic
variable and another thread is reading it at the same time, that second
thread is going to get either the old value or the new value, but it's
guaranteed that it will not get some third garbage value.
 
It also guarantees that two threads trying to assign something to the
atomic variable will not interfere with each other so that garbage ends
up in the variable. The final value will be one or the other (depending
on which thread was allowed to access it first and which one after that),
and while the variable may contain for a brief moment the value written
by the first thread before it gets the value written by the second thread,
at no point will it contain any garbage value that's neither (nor the
original).
 
Atomic variables (at least with std::atomic) are also what you would
call "volatile", in that any read and assignment will happen exactly
where the operation appears in the code and nowhere else. The compiler
will not optimize it away nor move it somewhere else (such as outside
a loop). It will read or assign it precisely where and how many times
you say.
 
Of course atomic variables can be misused. They are not locks, fences
or semaphores. For example using atomic variable for a spinlock is
most probably not going to work unless you use an atomic compare-and-swap
instruction or similar. Simply doing a
"if(atomic_var == true) { atomic_var = false; dosomething(); }"
will not stop two threads from incorrectly entering that critical
section at the same time. Atomic variables need to be used correctly.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 03:35PM +0200

>> What I meant was that you can be assured that std::allocator<>
>> directly or indirectly uses malloc() because what I said.
 
> No, you cannot be assured of that. ...
 
It has nothting to do with the standard.
I told you why this is the most reasonable assumption.
Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 04:10PM +0300

16.06.2021 15:25 Sam kirjutas:
> Also one could use atomic variables, manually, with memory barriers and
> reinvent the wheel called "sequencing", if there's some pressing need to
> do so and std::mutex doesn't fit the bill.
 
As far as I can see the atomics are by default using memory barriers.
The default memory ordering is std::memory_order_seq_cst which means
memory barriers and lots of other guarantees:
 
https://en.cppreference.com/w/cpp/atomic/memory_order :
 
"Atomic operations tagged memory_order_seq_cst not only order memory the
same way as release/acquire ordering (everything that happened-before a
store in one thread becomes a visible side effect in the thread that did
a load), but also establish a single total modification order of all
atomic operations that are so tagged."
 
What you are describing seems more like std::memory_order_relaxed, which
is not the default. What I have misunderstood?
David Brown <david.brown@hesbynett.no>: Jun 16 03:59PM +0200


> Sure, but that only matters in a multi threaded program. And if atomic
> isn't guaranteed to be thread safe then surely you'd be better off just
> using mutex locks?
 
The atomics /are/ guaranteed to be thread safe. But they are not
guaranteed to be synchronising (depending on the memory order given).
 
The prime point of atomic increments and decrements is that you'll end
up with the right number in the result, regardless of the order things
are done. This makes relaxed atomics very efficient and lightweight
compared to big locks.
MrSpook_74D@ov88_wt8h.co.uk: Jun 16 01:54PM

On Wed, 16 Jun 2021 14:43:59 +0200
 
> void foo(int * a) __attribute__((nonull));
 
>However, I would say that gcc's syntax is a lot clearer (assuming, of
>course, you are using a compiler that accepts it).
 
Just tried this with gcc 8.3.0:
 
void func(int a[static 10])
{
}
 
 
int main()
{
int a[5];
func(a);
return 0;
}
 
 
Compiles without errors or warnings even with -Wall -pedantic -Wextra -std=c99
which is obviously not whats intended. Presumably implemented only in the
parser, not the core compiler.
MrSpook_ucGx3e4l@x8gqtuqjwl9z3g.com: Jun 16 01:47PM

On Wed, 16 Jun 2021 08:25:18 -0400
 
>The C++ library's std::shared_ptr is a perfect example. If its destructor
>decrements the shared reference count and becomes zero it logically means
>that no other instance of std::shared_ptr exists, so it's safe to destroy
 
Sure, but that only matters in a multi threaded program. And if atomic
isn't guaranteed to be thread safe then surely you'd be better off just
using mutex locks?
David Brown <david.brown@hesbynett.no>: Jun 16 04:07PM +0200


>> I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does
>> not exist for C++.
 
> Is it C99?
 
Yes, I believe so.
Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 06:10PM +0300

16.06.2021 14:40 Bonita Montero kirjutas:
>> executables where our library might be loaded into still use
>> whatever they want, typically standard malloc().
 
> Better replace the global memory-allocation through mimalloc.
 
This would still require access or influence over the main executable,
which I (and many other C++ developers) do not have.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 05:37PM +0200

>>> C code, too, ...
 
>> They don't.
 
> As usual, you are wrong. It's quite common in some circles. ...
 
It's quite stupid to do that. You have to implement an allocator which
can be rebound for all types with typename allocator_traits<alloc>
::template rebind_alloc<T> since you can't anticipate what the STL
-containers rebind to, i.e. you have to write an allocator whith the
full capabilities of malloc(). That's much work and it's almost
impossible to beat the performance of common replacement-allocators.
So it's just the best way to replace malloc() which is indirectly or
directly used by std::allocator<> on all platforms.
 
> None of which you've ever had any experience with; nor have you exhibited
> the programming skills (or interpersonal skills) to survive in those circles.
 
I've already built a custom std::allocator<> replacement for special
cases where the allocator can be assumed not to be rebound (vector<>).
And I would be able to write an efficient allocator like mimalloc; but
I wouldn't have invented the basic structures for that - and you not
as well.
MrSpook_g3w@2ur2yrijxtw7d3jt394yu9dp.org: Jun 16 01:48PM

On Wed, 16 Jun 2021 14:44:37 +0200
>> course, you are using a compiler that accepts it).
 
>I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does
>not exist for C++.
 
Is it C99?
Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 05:50PM +0200

> Incrementing a shared counter without first acquiring a lock is a perfect
> use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel
> LOCK INC).
 
No, fetch_and_add is LOCK XADD.
MrSpook_hjesjs@8pot25r5sg1xe.info: Jun 16 03:45PM

On Wed, 16 Jun 2021 15:09:58 GMT
 
>Incrementing a shared counter without first acquiring a lock is a perfect
>use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel
>LOCK INC).
 
I'm confused. Either std::atomic is thread safe or it isn't. Which is it?
David Brown <david.brown@hesbynett.no>: Jun 16 07:55PM +0200


> Compiles without errors or warnings even with -Wall -pedantic -Wextra -std=c99
> which is obviously not whats intended. Presumably implemented only in the
> parser, not the core compiler.
 
clang warns here, gcc does not. It's a case of clang being a little
better and more helpful at the static analysis in this case. The C
syntax provides compilers with an opportunity to warn you, but does not
require them to do so.
 
You could file this as a bug in gcc if you like (it's a missing feature,
rather than a bug, but it goes in the same bugzilla list).
David Brown <david.brown@hesbynett.no>: Jun 16 07:58PM +0200

On 16/06/2021 16:38, James Kuyper wrote:
>> which language doesn't? Hands up those C experts who know what the
>> "static" in "void bar(int a[static 10]);" is doing?),
 
> Hand up!
 
I bet /you/ read the challenge correctly, and are raising your hand
because you /do/ know what it means - unlike Mr Spook who raised his
hand because he /doesn't/ know. Still, that gave me the excuse to give
the answer - which I must have got right, otherwise you'd have corrected
me by now :-)
Sam <sam@email-scan.com>: Jun 16 05:40PM -0400

Bonita Montero writes:
 
>>> directly or indirectly uses malloc() because what I said.
 
>> No, you cannot be assured of that. ...
 
> It has nothting to do with the standard.
 
Everything has to do with the standard.
 
> I told you why this is the most reasonable assumption.
 
No, you told me why you think it's "the most reasonable assumption". That
doesn't make it so, and it's actually quite unreasonable. No experienced C++
developer will make that assumption.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 12 11:15AM +0200

>> It calls it via std::allocator.
 
> What is it? Where and when is std::allocator required to call what?
> You continue not knowing what you talk about.
 
std::allocator isn't required to do that, but at last everyone expects
it to call malloc() in some way; it doesn't matter if it does this via
new or directly. This is to meet the expectations that the
memory-allo-ocator is globally replaceable.
Bo Persson <bo@bo-persson.se>: Jun 12 01:07PM +0200

On 2021-06-12 at 11:03, Bonita Montero wrote:
> That's what the user expects because in this way you could replace
> the whole C++ memory-alloction by replacing malloc() like a few
> memory-allocators like mimalloc, jemalloc, tcmallog e.g. do it.
 
So where does the standard say that "involves a call" only means a
direct call? And that an indirect call is still required even when a
direct call is not?
Bonita Montero <Bonita.Montero@gmail.com>: Jun 12 01:19PM +0200

>> that so that the writers of the standard-libaries imeplement
>> them in an expectable behaviour.
 
> C and C++ are two different languages.
 
But a lot of people still expect that C++ memory-allocation indirectly
bases on malloc() and is thereby replaceable.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 12 01:22PM +0200

> So where does the standard say that "involves a call" only means a
> direct call? And that an indirect call is still required even when a
> direct call is not?
 
The standard doesn't guarantee that, but the standard libary implemen-
tors don't use sth. different than indirectly malloc() to make the whole
memory-allocation of the code replaceable. If a sandard libary wouldn't
be implemented in that way mimalloc, jemalloc, tcmalloc, Hoard ...
woudln't work.
David Brown <david.brown@hesbynett.no>: Jun 12 02:04PM +0200

On 12/06/2021 13:19, Bonita Montero wrote:
 
>> C and C++ are two different languages.
 
> But a lot of people still expect that C++ memory-allocation indirectly
> bases on malloc() and is thereby replaceable.
 
You have already established that what /you/ personally expect is a
different thing from what languages, compilers and tools document that
they do, and what other programmers expect. This is just another one of
your unjustified assumptions based on nothing but your own lack of
imagination and inability or unwillingness to learn how C++ and the
tools are actually specified.
Vir Campestris <vir.campestris@invalid.invalid>: Jun 16 09:38PM +0100

On 06/06/2021 23:22, Alf P. Steinbach wrote:
 
> One can tell gcc (or at least g++) to use the less noisy and more
> conventional, in short more reasonable, Intel syntax via option
> `-masm=intel`, unless I recall the details of that incorrectly.
 
Ah, that explains it all.
 
Except why the GCC/ARM disassembly I occasionally look at in my day job
is in Intel order...
 
Thanks
 
Andy
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: