Thursday, October 3, 2019

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

Sam <sam@email-scan.com>: Oct 03 07:00AM -0400

Bonita Montero writes:
 
>> read and return, so the program cannot physically work. ...
 
> I know the reasons why this doesn't work.
> I only wanted to have a workaround without making ABC static.
 
There is no "workaround". C++ does not work this way. If something is a
class member, it can only exist as an instance of the class. Therefore you
can only access it as a member of an instance of the class. It is not an
independent object, with a life of its own. End of story.
James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 03 06:25AM -0700

On Thursday, October 3, 2019 at 5:16:14 AM UTC-4, Bonita Montero wrote:
> > There is no A object created anywhere, so there is no existing ABC
> > member to read and return, so the program cannot physically work. ...
 
> I know the reasons why this doesn't work.
 
If so, then it was counter-productive to start your first message in
this thread with the question "Why doesn't this work?"
 
> I only wanted to have a workaround without making ABC static.
 
Well, the simple, obvious solution is to make ABC static. I can't
imagine why it's important to you that it not be static. If you do have
a good reason for that requirement, you should explain the reason, so
people can better help you.
 
In the meantime, the following approach meets your stated requirement:
 
int const ABC = 123;
 
struct A
{
struct B
{
int f();
};
};
 
So does the following:
 
struct A
{
struct B
{
int const ABC = 123;
int f();
};
};
 
But those solutions are so obvious that I assume that they violate some
additional requirements that you failed to mention. If so, you need to
explain all the relevant requirements, so people will be better able to
help you.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 03:41PM +0200

> additional requirements that you failed to mention. If so, you need to
> explain all the relevant requirements, so people will be better able to
> help you.
 
I need the constant in the outer class.
With static I found a bug in the gcc, that I couln't use the constant in
the constructor. The constants were defined this way:
 
static
std::uint32_t const UNPINNED_NODE = 0,
FREE_NODE = 0xFFFFFFFFu;
 
 
I assigned FREE_NODE to a member in this way.
 
nd->pinCounter = (uint32_t const)FREE_NODE; // gcc-bug?
 
Without the cast I got a linker-error (MSVC compiled the code).
Surprisingly all other "accesses" to FREE_NODE in the outer class
didn't give this linker-error. I don't know why gcc acesses FREE_NODE
like it's not a const at this point in the constructor. So I asked for
a work-around bcause I needed the constant in the innner class as well
in the outer.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 03 05:02PM +0300

On 3.10.2019 16:41, Bonita Montero wrote:
> like it's not a const at this point in the constructor. So I asked for
> a work-around bcause I needed the constant in the innner class as well
> in the outer.
 
Your problem is explained here:
 
https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
 
And no, it's not a bug in gcc.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 04:07PM +0200

> Your problem is explained here:
> https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
 
That's a different problem because it's not about static const members.
 
> https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
> And no, it's not a bug in gcc.
 
I tried defining the member within one translation-unit, but this didn't
help. And if I removed the line I quoted accessed to FREE_NODE by ohter
methods of my class weren't complained by gcc.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 04:13PM +0200


> I tried defining the member within one translation-unit, but this didn't
> help. And if I removed the line I quoted accessed to FREE_NODE by ohter
> methods of my class weren't complained by gcc.
 
And read-access to FREE_NODE is compile-time constant anyway. Only if
I nonsensically cast FREE_NODE to non-const and assign ít a value there
should be a linker-error.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 03 05:18PM +0300

On 3.10.2019 17:07, Bonita Montero wrote:
>> https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
 
> That's a different problem because it's not about static const members.
 
>> https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
 
The second link is specifically about static const members. Quoting from
there:
 
"And, just like other static data members, it must be defined in exactly
one compilation unit, though this time without the = initializer part"
 
>> And no, it's not a bug in gcc.
 
> I tried defining the member within one translation-unit, but this didn't
> help.
 
Then you did something wrong.
 
> And if I removed the line I quoted accessed to FREE_NODE by ohter
> methods of my class weren't complained by gcc.
 
Such linker related bugs in your code are "no diagnostic required".
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 04:36PM +0200

> there:
> "And, just like other static data members, it must be defined in exactly
> one compilation unit, though this time without the = initializer part"
 
That's not alway true. The have to be declared only if they're written
or read. But if they're compile-time-constant like my uint32_t, they
are neither.
 
>> I tried defining the member within one translation-unit, but this didn't
>> help.
 
> Then you did something wrong.
 
No, I didn't
 
>> And if I removed the line I quoted accessed to FREE_NODE by ohter
>> methods of my class weren't complained by gcc.
 
> Such linker related bugs in your code are "no diagnostic required".
 
No, that's a clear sign that gcc has a bug at this point. At other
placess FREE_NODE is compile-time-constant but in the constructor
it is physically accessed.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 05:15PM +0200

> Your problem is explained here:
> https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
> https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
 
// Fred.h
class Fred {
public:
private:
static int j_;
};
 
// Fred.cpp
#include "Fred.h"
int Fred::j_ = some_expression_evaluating_to_an_int;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
That's not ncessary because Fred::j_ is compile-time constant.
Bo Persson <bo@bo-persson.se>: Oct 03 05:28PM +0200

On 2019-10-03 at 16:36, Bonita Montero wrote:
 
> No, that's a clear sign that gcc has a bug at this point. At other
> placess FREE_NODE is compile-time-constant but in the constructor
> it is physically accessed.
 
No, the bug is in your code.
 
The separate definition is formally required (at least in older C++).
 
However, the optimizer might often remove all references to the
constant, and then the linker will not notice that it is missing and let
you get away with it.
 
This case is so common that most people probably belive it is the norm.
 
 
Bo Persson
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 05:32PM +0200

>> it is physically accessed.
 
> No, the bug is in your code.
 
> The separate definition is formally required (at least in older C++).
 
No, the separate definition is not required if it can be evaluated to
a compile-time constant. You can even define arrays with compile-time
sizes on those const-members.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 05:35PM +0200

> However, the optimizer might often remove all references to the
> constant, and then the linker will not notice that it is missing
> and let you get away with it.
 
Consider this:
 
int const ABC = 123;
 
int fABC()
{
return ::ABC;
}
 
If I compile it without optimizations with MSVC++, I'll get this:
 
mov eax, 123
ret 0
 
And gcc compiles this without optimizations:
 
pushq %rbp
movq %rsp, %rbp
movl $123, %eax
popq %rbp
ret
Bo Persson <bo@bo-persson.se>: Oct 03 05:46PM +0200

On 2019-10-03 at 17:32, Bonita Montero wrote:
 
> No, the separate definition is not required if it can be evaluated to
> a compile-time constant. You can even define arrays with compile-time
> sizes on those const-members.
 
Quoting myself:
 
"However, the optimizer might often remove all references to the
constant, and then the linker will not notice that it is missing
and let you get away with it. "
 
 
In C++17 you can use constexpr instead of const, and formally get away
from the requirement for a separate definition.
 
You might want to read the last paragraph on this page:
 
https://en.cppreference.com/w/cpp/language/static
 
"If a static data member is declared constexpr, it is implicitly inline
and does not need to be redeclared at namespace scope. This
redeclaration without an initializer (formerly required as shown above)
is still permitted, but is deprecated. (since C++17)"
 
 
 
Bo Persson
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 06:55PM +0200

> "However, the optimizer might often remove all references to the
> constant, and then the linker will not notice that it is missing
> and let you get away with it. "
 
No, that's not a matter of the optimizer. The language itself imposes
that a const variable has to be compile-time constant unter certain
cirtcumstances. Without that the following wouldn't be possible:
 
size_t const ARRAY_SIZE = 123;
int array[ARRAY_SIZE];
 
How could that be possible if this would be a matter of the optimizer?
Paavo Helde <myfirstname@osa.pri.ee>: Oct 03 08:32PM +0300

On 3.10.2019 19:55, Bonita Montero wrote:
 
> size_t const ARRAY_SIZE = 123;
> int array[ARRAY_SIZE];
 
> How could that be possible if this would be a matter of the optimizer?
 
Exactly, this line is the *definition* of a constant, providing a linker
symbol if needed. What you can have inside a class is just a *declaration*.
 
If you acknowledge the above ARRAY_SIZE definition as valid code, then
why do you refuse to provide a similar definition for your const static
class member?
Bonita Montero <Bonita.Montero@gmail.com>: Oct 03 07:35PM +0200

>> How could that be possible if this would be a matter of the optimizer?
 
> Exactly, this line is the *definition* of a constant, providing a linker
> symbol if needed. What you can have inside a class is just a *declaration*.
 
The actual discussion was whether the optimization is a matter of the
language or of the optimizer. We were not discussion definitions vs.
declarations at this point.
 
> If you acknowledge the above ARRAY_SIZE definition as valid code, then
> why do you refuse to provide a similar definition for your const static
> class member?
 
Because it is not necessary from what the language allows.
Joseph Hesse <joeh@gmail.com>: Oct 03 09:03AM -0500

I am puzzled how the following program works.
 
=====================================================
#include <iostream>
using namespace std;
 
int main()
{
char x[] = {"Hello"}; // x is a 0 terminated character array
 
for(const auto &i : x)
cout << i << " ";
 
cout << "\n";
}
=====================================================
 
Putting a 0 at the end of a character array to indicate the end is a
convention and not part of the language. There are library functions
that understand this convention but the library is not part of the
language definition.
 
How does the range-for-statement, which is a language construct, know
that it has to stop when it sees a 0?
 
Thank you,
Joe
Paavo Helde <myfirstname@osa.pri.ee>: Oct 03 05:12PM +0300

On 3.10.2019 17:03, Joseph Hesse wrote:
> language definition.
 
> How does the range-for-statement, which is a language construct, know
> that it has to stop when it sees a 0?
 
It doesn't know and it doesn't stop at any zero byte. Instead, it knows
the size of the x array.
 
#include <iostream>
using namespace std;
 
int main()
{
char x[] = { "Hello\0\0World" };
 
for (const auto &i : x)
cout << int(i) << " ";
 
cout << "\n";
}
 
 
72 101 108 108 111 0 0 87 111 114 108 100 0
Keith Thompson <kst-u@mib.org>: Oct 03 10:21AM -0700

> language definition.
 
> How does the range-for-statement, which is a language construct, know
> that it has to stop when it sees a 0?
 
It doesn't. When I compile and run your program, the output *looks
like*
 
H e l l o
 
but in fact it prints the null character:
 
./c | cat -A
H e l l o ^@ $
 
As Paavo Helde correctly states, it knows the size of the array, not the
length of the string contained in the array.
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
scott@slp53.sl.home (Scott Lurndal): Oct 03 01:23PM

>Buf [A-1] = B;
>return (A + B * D - C);
>}
 
00000000004004f0 <Funz>:
4004f0: 55 push %rbp
4004f1: 48 89 e5 mov %rsp,%rbp
4004f4: 53 push %rbx
4004f5: 48 83 ec 38 sub $0x38,%rsp // Reserve frame
4004f9: 89 7d cc mov %edi,-0x34(%rbp)
4004fc: 89 75 c8 mov %esi,-0x38(%rbp)
4004ff: 48 89 e0 mov %rsp,%rax
400502: 48 89 c6 mov %rax,%rsi
400505: c7 45 ec 03 00 00 00 movl $0x3,-0x14(%rbp)
40050c: 8b 45 cc mov -0x34(%rbp),%eax
40050f: 48 63 f8 movslq %eax,%rdi
400512: 48 83 ef 01 sub $0x1,%rdi
400516: 48 89 7d e0 mov %rdi,-0x20(%rbp)
40051a: 48 63 f8 movslq %eax,%rdi
40051d: 49 89 f8 mov %rdi,%r8
400520: 41 b9 00 00 00 00 mov $0x0,%r9d
400526: 48 63 f8 movslq %eax,%rdi
400529: 48 89 fa mov %rdi,%rdx
40052c: b9 00 00 00 00 mov $0x0,%ecx
400531: 48 98 cltq
400533: 48 c1 e0 02 shl $0x2,%rax
400537: 48 8d 50 03 lea 0x3(%rax),%rdx
40053b: b8 10 00 00 00 mov $0x10,%eax
400540: 48 83 e8 01 sub $0x1,%rax
400544: 48 01 d0 add %rdx,%rax
400547: bb 10 00 00 00 mov $0x10,%ebx
40054c: ba 00 00 00 00 mov $0x0,%edx
400551: 48 f7 f3 div %rbx
400554: 48 6b c0 10 imul $0x10,%rax,%rax
400558: 48 29 c4 sub %rax,%rsp // Allocate Buf[A]
40055b: 48 89 e0 mov %rsp,%rax // %rax = &Buf[0]
40055e: 48 83 c0 03 add $0x3,%rax // dword align pointer
400562: 48 c1 e8 02 shr $0x2,%rax
400566: 48 c1 e0 02 shl $0x2,%rax
40056a: 48 89 45 d8 mov %rax,-0x28(%rbp) // Save Buf addr in frame
40056e: c7 45 d4 02 00 00 00 movl $0x2,-0x2c(%rbp)
400575: 8b 45 cc mov -0x34(%rbp),%eax
400578: 8d 50 ff lea -0x1(%rax),%edx
40057b: 48 8b 45 d8 mov -0x28(%rbp),%rax
40057f: 48 63 d2 movslq %edx,%rdx
400582: 8b 4d c8 mov -0x38(%rbp),%ecx
400585: 89 0c 90 mov %ecx,(%rax,%rdx,4)
400588: 8b 45 c8 mov -0x38(%rbp),%eax
40058b: 0f af 45 d4 imul -0x2c(%rbp),%eax
40058f: 89 c2 mov %eax,%edx
400591: 8b 45 cc mov -0x34(%rbp),%eax
400594: 01 d0 add %edx,%eax
400596: 2b 45 ec sub -0x14(%rbp),%eax
400599: 48 89 f4 mov %rsi,%rsp
40059c: 48 8b 5d f8 mov -0x8(%rbp),%rbx
4005a0: c9 leaveq
4005a1: c3 retq
David Brown <david.brown@hesbynett.no>: Oct 03 03:38PM +0200

On 03/10/2019 13:39, Soviet_Mario wrote:
 
> the code I'd like to see in .asm intermediate code (NO OPTIMIZATION
> ACTIVE) was
 
Examining generated assembly code with no optimisation is usually
pointless. If you care about the efficiency of the assembly, you will
have optimisation enabled on the compiler. Looking at the assembly
generated with optimisation off tells you practically nothing.
 
The tool you want here is the webpage <https://godbolt.org>. It is an
online compiler site, letting you type small bits of code and compile it
with a wide variety of compilers ("x86-64 gcc (trunk)" is popular, but
not the only choice) and using whatever options you want (like "-x c
-std=c11 -O2 -Wall -Wpedantic" as a reasonable starting point).
 
Use that site to see the generated code, and perhaps these newsgroups to
ask /why/ you get particular code. It's better than asking people in
these groups to compile code snippets for you, at least for standard
compilers.
scott@slp53.sl.home (Scott Lurndal): Oct 03 02:51PM

>pointless. If you care about the efficiency of the assembly, you will
>have optimisation enabled on the compiler. Looking at the assembly
>generated with optimisation off tells you practically nothing.
 
Although the example he provided optimizes (-O3) down to:
 
0000000000400400 <main>:
400400: b8 07 00 00 00 mov $0x7,%eax
400405: c3 retq
scott@slp53.sl.home (Scott Lurndal): Oct 03 01:17PM

>64, 128 bit floating point numbers, in either little endian or big endian.
>Could you explain the "obvious endian independent method" that will encode and
>decode that?
 
If the incoming big-endian data is treated as a sequence of bytes, you
can easily reconstruct a binary value simply shifting the data into the
correct sized container a byte at a time.
 
uint64_t value = 0ul;
char *bp = &buffer[first_byte_of_uint64_big_endian_data];
 
for (size_t i = 0; i < sizeof(uint64_t); i++) {
value <<= 8;
value |= *bp++;
}
 
This works regardless of the host endianness.
David Brown <david.brown@hesbynett.no>: Oct 03 04:03PM +0200

On 03/10/2019 15:17, Scott Lurndal wrote:
> value |= *bp++;
> }
 
> This works regardless of the host endianness.
 
You want "uint8_t" (or, for even more portability, uint_least8_t)
instead of "char" for your pointer. Unpleasant things will happen if
"char" is signed.
 
Apart from that, that is the "obvious" method I meant.
 
Some compilers are smart enough to optimise this kind of code into a
single load (if the cpu supports unaligned accesses) and a byte-swap (if
the cpu is little-endian). Clang manages it for 16-bit and 32-bit
versions of this code, but not the 64-bit version. gcc won't do it at
all in this case (I've seen it do such optimisation with other code).
Daniel <danielaparker@gmail.com>: Oct 03 07:13AM -0700

On Thursday, October 3, 2019 at 10:03:52 AM UTC-4, David Brown wrote:
> instead of "char" for your pointer. Unpleasant things will happen if
> "char" is signed.
 
> Apart from that, that is the "obvious" method I meant.
 
Thanks, Scott and David, obvious, perhaps, but I didn't know about it.
 
Daniel
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: