Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > the c++ standard on static constants

Reply
Thread Tools

the c++ standard on static constants

 
 
John Ratliff
Guest
Posts: n/a
 
      10-16-2005
I'm trying to find out whether g++ has a bug or not. Wait, don't leave,
it's a standard C++ question, I promise.

This program will compile and link fine under mingw/g++ 3.4.2, but fails
to link under Linux/g++ 3.3.3.

---------------------------------------------
#include <iostream>
#include <utility>

class foo {
private:
char sram[0x2000];

public:
static const int A = 0x8;
static const int B = 0x1FF8;

foo() {
sram[8] = 1;
sram[9] = 2;
sram[0x1FF8] = 3;
sram[0x1FF9] = 4;
}

std:air<unsigned char, unsigned char> method(bool redundant) const {
int offset = (redundant ? B : A);

return std:air<unsigned char,
unsigned char>(sram[offset], sram[offset + 1]);
}
};

int main(int, char **) {
foo f;
std:air<unsigned char, unsigned char> p1(f.method(false));
std:air<unsigned char, unsigned char> p2(f.method(true));

std::cout << "p1 = (" << (int)p1.first << ","
<< (int)p1.second << ")\n";
std::cout << "p2 = (" << (int)p2.first << ","
<< (int)p2.second << ")\n";

return 0;
}
---------------------------------------------

The reason is that in mingw/g++ 3.4.2, the static constants A and B are
replaced during compile time and didn't need storage space. The linker
therefore didn't need to find them. However, Linux/g++ 3.3.3 generates
code that requires them to have storage space.

Am I supposed to declare storage space for these constants, or is it
legal here to assume they will become compile-time constnats? What does
the C++ standard say?

Thanks,

--John Ratliff
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      10-16-2005
John Ratliff wrote:
> I'm trying to find out whether g++ has a bug or not. Wait, don't
> leave, it's a standard C++ question, I promise.
>
> This program will compile and link fine under mingw/g++ 3.4.2, but
> fails to link under Linux/g++ 3.3.3.
>
> ---------------------------------------------
> #include <iostream>
> #include <utility>
>
> class foo {
> private:
> char sram[0x2000];
>
> public:
> static const int A = 0x8;
> static const int B = 0x1FF8;
>
> foo() {
> sram[8] = 1;
> sram[9] = 2;
> sram[0x1FF8] = 3;
> sram[0x1FF9] = 4;
> }
>
> std:air<unsigned char, unsigned char> method(bool redundant)
> const { int offset = (redundant ? B : A);
>
> return std:air<unsigned char,
> unsigned char>(sram[offset], sram[offset +
> 1]); }
> };
>
> int main(int, char **) {
> foo f;
> std:air<unsigned char, unsigned char> p1(f.method(false));
> std:air<unsigned char, unsigned char> p2(f.method(true));
>
> std::cout << "p1 = (" << (int)p1.first << ","
> << (int)p1.second << ")\n";
> std::cout << "p2 = (" << (int)p2.first << ","
> << (int)p2.second << ")\n";
>
> return 0;
> }
> ---------------------------------------------


The program is well-formed. 'A' and 'B' are never used outside of
the class definition, so they don't need to be defined. That's what
1998 version of the Standard used to say. It was changed a bit in the
2003 version (IIRC) but to give programmers even more leeway.

> The reason is that in mingw/g++ 3.4.2, the static constants A and B
> are replaced during compile time and didn't need storage space. The
> linker therefore didn't need to find them. However, Linux/g++ 3.3.3
> generates code that requires them to have storage space.


In what way? Can you figure what is trying to refer to them?

> Am I supposed to declare storage space for these constants, or is it
> legal here to assume they will become compile-time constnats? What
> does the C++ standard say?


Since their address is never taken, the 'foo::A' and 'foo::B' are, in
fact, compile-time constant expressions that do not require storage.
The objects, therefore, don't need to be defined outside of the class
definition. g++ 3.3.3 is probably too old. It's even too old and non-
compliant in this particular case even with 1998 version of the C++
Standard. The standard was amended to allow const statics to be only
defined in the class definition if their address is not taken _even_
if they are "used" outside the class. [I am too lazy, though, to look
it up in the Standard...]

V


 
Reply With Quote
 
 
 
 
John Ratliff
Guest
Posts: n/a
 
      10-16-2005
Victor Bazarov wrote:
> John Ratliff wrote:
>
>>I'm trying to find out whether g++ has a bug or not. Wait, don't
>>leave, it's a standard C++ question, I promise.
>>
>>This program will compile and link fine under mingw/g++ 3.4.2, but
>>fails to link under Linux/g++ 3.3.3.
>>
>>---------------------------------------------
>>#include <iostream>
>>#include <utility>
>>
>>class foo {
>>private:
>> char sram[0x2000];
>>
>>public:
>> static const int A = 0x8;
>> static const int B = 0x1FF8;
>>
>> foo() {
>> sram[8] = 1;
>> sram[9] = 2;
>> sram[0x1FF8] = 3;
>> sram[0x1FF9] = 4;
>> }
>>
>> std:air<unsigned char, unsigned char> method(bool redundant)
>> const { int offset = (redundant ? B : A);
>>
>> return std:air<unsigned char,
>> unsigned char>(sram[offset], sram[offset +
>> 1]); }
>>};
>>
>>int main(int, char **) {
>> foo f;
>> std:air<unsigned char, unsigned char> p1(f.method(false));
>> std:air<unsigned char, unsigned char> p2(f.method(true));
>>
>> std::cout << "p1 = (" << (int)p1.first << ","
>> << (int)p1.second << ")\n";
>> std::cout << "p2 = (" << (int)p2.first << ","
>> << (int)p2.second << ")\n";
>>
>> return 0;
>>}
>>---------------------------------------------

>
>
> The program is well-formed. 'A' and 'B' are never used outside of
> the class definition, so they don't need to be defined. That's what
> 1998 version of the Standard used to say. It was changed a bit in the
> 2003 version (IIRC) but to give programmers even more leeway.
>
>
>>The reason is that in mingw/g++ 3.4.2, the static constants A and B
>>are replaced during compile time and didn't need storage space. The
>>linker therefore didn't need to find them. However, Linux/g++ 3.3.3
>>generates code that requires them to have storage space.

>
>
> In what way? Can you figure what is trying to refer to them?


This is the assembly generated from Linux/g++ 3.3.3 for foo::method when
using g++ -S temp.cc. No extra optimization declared, though it doesn't
fix it if you do -O2. The really stupid thing is that if you replace the
ternary operator with an if statement, it will treat A and B as
compile-time constants properly.

-----------------------------------------------------
_ZNK3foo6methodEb:
..LFB1535:
pushl %ebp
..LCFI14:
movl %esp, %ebp
..LCFI15:
subl $24, %esp
..LCFI16:
movl 16(%ebp), %eax
movb %al, -1(%ebp) ; stick redundant on the stack
cmpb $0, -1(%ebp) ; if redundant is false
je .L6 ; goto .L6
movl _ZN3foo1BE, %eax ; move B into eax
; -- NOT a compile-time constant
movl %eax, -16(%ebp) ; this is also stupid,
; but not related to my problem
jmp .L7 ; goto .L7
..L6:
movl _ZN3foo1AE, %eax ; move A into eax
; again, not a compile-time constant
movl %eax, -16(%ebp) ; more g++ stupidity
..L7:
movl -16(%ebp), %eax ; and where we realize the stupidity
movl %eax, -8(%ebp) ; the rest is just creating the
; std:air and returning it
subl $4, %esp
movl 12(%ebp), %eax
addl -8(%ebp), %eax
incl %eax
movb (%eax), %al
movb %al, -9(%ebp)
leal -9(%ebp), %eax
pushl %eax
movl 12(%ebp), %edx
movl -8(%ebp), %eax
movb (%eax,%edx), %al
movb %al, -10(%ebp)
leal -10(%ebp), %eax
pushl %eax
pushl 8(%ebp)
..LCFI17:
call _ZNSt4pairIhhEC1ERKhS2_
addl $16, %esp
movl 8(%ebp), %eax
leave
ret $4
-----------------------------------------------------

This is the assembly output for mingw/g++ 3.4.2

-----------------------------------------------------
__ZNK3foo6methodEb:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl 12(%ebp), %eax
movb %al, -1(%ebp) ; move redundant (%al) to stack
cmpb $0, -1(%ebp) ; if redundant is false
je L12 ; goto L12
movl $8184, -16(%ebp) ; put B into offset
; B IS a compile-time constant
jmp L13 ; goto L13
L12:
movl $8, -16(%ebp) ; move A into offset
; again, A is a compile-time constant
L13:
movl -16(%ebp), %eax ; return std:air blah blah blah
movl %eax, -8(%ebp)
movl 8(%ebp), %eax
addl -8(%ebp), %eax
incl %eax
movzbl (%eax), %eax
movb %al, -11(%ebp)
leal -11(%ebp), %eax
movl %eax, 8(%esp)
movl 8(%ebp), %edx
movl -8(%ebp), %eax
movzbl (%eax,%edx), %eax
movb %al, -12(%ebp)
leal -12(%ebp), %eax
movl %eax, 4(%esp)
leal -10(%ebp), %eax
movl %eax, (%esp)
call __ZNSt4pairIhhEC1ERKhS2_
movzwl -10(%ebp), %eax
leave
ret
-----------------------------------------------------

The stupid copy from a->stack and back is gone in 3.4.2 also, but that's
not really related to my problem.

>
>
>>Am I supposed to declare storage space for these constants, or is it
>>legal here to assume they will become compile-time constnats? What
>>does the C++ standard say?

>
>
> Since their address is never taken, the 'foo::A' and 'foo::B' are, in
> fact, compile-time constant expressions that do not require storage.
> The objects, therefore, don't need to be defined outside of the class
> definition. g++ 3.3.3 is probably too old. It's even too old and non-
> compliant in this particular case even with 1998 version of the C++
> Standard. The standard was amended to allow const statics to be only
> defined in the class definition if their address is not taken _even_
> if they are "used" outside the class. [I am too lazy, though, to look
> it up in the Standard...]


I was just discussing it on the gcc-help list and need evidence to prove
it's a g++ bug.

I think I will go compile g++ 3.4.2 for use on Linux.

Thanks,

--John Ratliff
 
Reply With Quote
 
Ian
Guest
Posts: n/a
 
      10-16-2005
John Ratliff wrote:
> I'm trying to find out whether g++ has a bug or not. Wait, don't leave,
> it's a standard C++ question, I promise.
>
> This program will compile and link fine under mingw/g++ 3.4.2, but fails
> to link under Linux/g++ 3.3.3.
>
> ---------------------------------------------
> #include <iostream>
> #include <utility>
>
> class foo {
> private:
> char sram[0x2000];
>
> public:
> static const int A = 0x8;
> static const int B = 0x1FF8;
>

[snip]

> Am I supposed to declare storage space for these constants, or is it
> legal here to assume they will become compile-time constnats? What does
> the C++ standard say?
>

In theory yes, but so long as you don't take the address of a static
const, no.

If you do take the address of a static constant, it has to be defined in
the program.

Ian
 
Reply With Quote
 
John Ratliff
Guest
Posts: n/a
 
      10-17-2005
Victor Bazarov wrote:
> The program is well-formed. 'A' and 'B' are never used outside of
> the class definition, so they don't need to be defined. That's what
> 1998 version of the Standard used to say. It was changed a bit in the
> 2003 version (IIRC) but to give programmers even more leeway.


From the 1998 C++ standard. 9.4.2 4

"If a static data member is of const integral or const enumeration type,
its declaration in the class definition can specify a constant
initializer which shall be an integral constant expression (5.19). In
that case, the member can appear in integral constant expressions within
its scope. The member shall still be defined in a namespace scope if it
is used in the program and the namespace scope definition shall not
contain an initializer."

"The member shall still be defined in the namespace scope" is the line
I'm looking at. Doesn't this mean I still have to declare it?

Thanks,

--John Ratliff
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-17-2005
* John Ratliff:
> Victor Bazarov wrote:
> > The program is well-formed. 'A' and 'B' are never used outside of
> > the class definition, so they don't need to be defined. That's what
> > 1998 version of the Standard used to say. It was changed a bit in the
> > 2003 version (IIRC) but to give programmers even more leeway.

>
> From the 1998 C++ standard. 9.4.2 4
>
> "If a static data member is of const integral or const enumeration type,
> its declaration in the class definition can specify a constant
> initializer which shall be an integral constant expression (5.19). In
> that case, the member can appear in integral constant expressions within
> its scope. The member shall still be defined in a namespace scope if it
> is used in the program and the namespace scope definition shall not
> contain an initializer."
>
> "The member shall still be defined in the namespace scope" is the line
> I'm looking at. Doesn't this mean I still have to declare it?


Yes.

<url:
http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>

One solution is to use an enum, which presumably is what those static
constants were meant to provide a more sensible, typed alternative to.

I've seen it claimed that the word 'used' means it's OK to use such constants
in compile time expressions, without defining them in namespace scope, but I
haven't seen that view substantiated with references to the standard.

There is a defect report, which has been there since -- November 1997:
<url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.

And there is a thorny issue, the whole shebang of static constants of other
types and initialization specified outside constructor can potentially be
dragged in, like, physicists didn't want to tackle the issue of quarks because
if fractional charges like 1/3 were introduced, where would it all end?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-17-2005
* Alf P. Steinbach:
> * John Ratliff:
> >
> > "The member shall still be defined in the namespace scope" is the line
> > I'm looking at. Doesn't this mean I still have to declare it?

>
> Yes.
>
> <url:
> http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
>
> One solution is to use an enum, which presumably is what those static
> constants were meant to provide a more sensible, typed alternative to.
>
> I've seen it claimed that the word 'used' means it's OK to use such constants
> in compile time expressions, without defining them in namespace scope, but I
> haven't seen that view substantiated with references to the standard.
>
> There is a defect report, which has been there since -- November 1997:
> <url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
>
> And there is a thorny issue, the whole shebang of static constants of other
> types and initialization specified outside constructor can potentially be
> dragged in, like, physicists didn't want to tackle the issue of quarks because
> if fractional charges like 1/3 were introduced, where would it all end?


Oh, there is a _proposed resolution_, <url:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.

If a static data member is of const integral or const enumeration type,
its declaration in the class definition can specify a constant-initializer
which shall be [note1] an integral constant expression (5.19). In that case,
the member can appear in integral constant expressions. No definition of the
member is required, unless an lvalue expression that designates it is
potentially evaluated and either used as operand to the built-in unary &
operator [note 2] or directly bound to a reference.

If a definition exists, it shall be at namespace scope and shall not
contain an initializer.


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
John Ratliff
Guest
Posts: n/a
 
      10-17-2005
Alf P. Steinbach wrote:
> * Alf P. Steinbach:
>
>>* John Ratliff:
>>
>>>"The member shall still be defined in the namespace scope" is the line
>>>I'm looking at. Doesn't this mean I still have to declare it?

>>
>>Yes.
>>
>><url:
>>http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
>>
>>One solution is to use an enum, which presumably is what those static
>>constants were meant to provide a more sensible, typed alternative to.
>>
>>I've seen it claimed that the word 'used' means it's OK to use such constants
>>in compile time expressions, without defining them in namespace scope, but I
>>haven't seen that view substantiated with references to the standard.
>>
>>There is a defect report, which has been there since -- November 1997:
>><url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
>>
>>And there is a thorny issue, the whole shebang of static constants of other
>>types and initialization specified outside constructor can potentially be
>>dragged in, like, physicists didn't want to tackle the issue of quarks because
>>if fractional charges like 1/3 were introduced, where would it all end?

>
>
> Oh, there is a _proposed resolution_, <url:
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.
>
> If a static data member is of const integral or const enumeration type,
> its declaration in the class definition can specify a constant-initializer
> which shall be [note1] an integral constant expression (5.19). In that case,
> the member can appear in integral constant expressions. No definition of the
> member is required, unless an lvalue expression that designates it is
> potentially evaluated and either used as operand to the built-in unary &
> operator [note 2] or directly bound to a reference.
>
> If a definition exists, it shall be at namespace scope and shall not
> contain an initializer.
>
>


Okay, so, technically, it IS required according to the current standard,
but most compilers implement the proposed resolution.

But to be a correct program, I need to define storage space until the
proposed resolution becomes part of the accepted standard.

Thanks,

--John Ratliff
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      10-17-2005
John Ratliff wrote:
> Alf P. Steinbach wrote:
>
>> * Alf P. Steinbach:
>>
>>> * John Ratliff:
>>>
>>>> "The member shall still be defined in the namespace scope" is the
>>>> line I'm looking at. Doesn't this mean I still have to declare it?
>>>
>>>
>>> Yes.
>>>
>>> <url:
>>> http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
>>>
>>>
>>> One solution is to use an enum, which presumably is what those static
>>> constants were meant to provide a more sensible, typed alternative to.
>>>
>>> I've seen it claimed that the word 'used' means it's OK to use such
>>> constants
>>> in compile time expressions, without defining them in namespace
>>> scope, but I
>>> haven't seen that view substantiated with references to the standard.
>>>
>>> There is a defect report, which has been there since -- November 1997:
>>> <url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
>>>
>>> And there is a thorny issue, the whole shebang of static constants of
>>> other
>>> types and initialization specified outside constructor can
>>> potentially be
>>> dragged in, like, physicists didn't want to tackle the issue of
>>> quarks because
>>> if fractional charges like 1/3 were introduced, where would it all end?

>>
>>
>>
>> Oh, there is a _proposed resolution_, <url:
>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.
>>
>> If a static data member is of const integral or const enumeration
>> type,
>> its declaration in the class definition can specify a
>> constant-initializer
>> which shall be [note1] an integral constant expression (5.19). In that
>> case,
>> the member can appear in integral constant expressions. No definition
>> of the
>> member is required, unless an lvalue expression that designates it is
>> potentially evaluated and either used as operand to the built-in unary &
>> operator [note 2] or directly bound to a reference.
>>
>> If a definition exists, it shall be at namespace scope and shall not
>> contain an initializer.
>>
>>

>
> Okay, so, technically, it IS required according to the current standard,
> but most compilers implement the proposed resolution.
>
> But to be a correct program, I need to define storage space until the
> proposed resolution becomes part of the accepted standard.


No, _technically_, since neither constant was used _outside_ the class
definition, there is no need for the definition at the namespace scope.
Now, if your compiler requires it, the compiler is non-compliant. But,
in that case, just to let the compilation through, you _technically_ need
the definition. Or, change the compiler.

V
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-17-2005
* Victor Bazarov:
>
> No, _technically_, since neither constant was used _outside_ the class
> definition, there is no need for the definition at the namespace scope.


I don't think that's implied.

But the standard's wording is not exactly clear...

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Proposed PEP: Treating Builtins as Constants in the Standard Library Raymond Hettinger Python 8 04-21-2004 11:31 AM
PEP 329: Treating Builtins as Constants in the Standard Library Raymond Hettinger Python 0 04-19-2004 12:54 PM
static constants Bill Woessner C++ 2 11-21-2003 05:58 AM
static constants... John David Ratliff C++ 1 11-07-2003 03:52 AM
Inheritance and static protected constants Collin VanDyck Java 8 10-22-2003 03:54 PM



Advertisments