473,548 Members | 2,633 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

the c++ standard on static constants

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::pair<unsig ned char, unsigned char> method(bool redundant) const {
int offset = (redundant ? B : A);

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

int main(int, char **) {
foo f;
std::pair<unsig ned char, unsigned char> p1(f.method(fal se));
std::pair<unsig ned char, unsigned char> p2(f.method(tru e));

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
Oct 16 '05 #1
14 2797
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::pair<unsig ned char, unsigned char> method(bool redundant)
const { int offset = (redundant ? B : A);

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

int main(int, char **) {
foo f;
std::pair<unsig ned char, unsigned char> p1(f.method(fal se));
std::pair<unsig ned char, unsigned char> p2(f.method(tru e));

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
Oct 16 '05 #2
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::pair<unsig ned char, unsigned char> method(bool redundant)
const { int offset = (redundant ? B : A);

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

int main(int, char **) {
foo f;
std::pair<unsig ned char, unsigned char> p1(f.method(fal se));
std::pair<unsig ned char, unsigned char> p2(f.method(tru e));

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.

-----------------------------------------------------
_ZNK3foo6method Eb:
..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::pair 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 _ZNSt4pairIhhEC 1ERKhS2_
addl $16, %esp
movl 8(%ebp), %eax
leave
ret $4
-----------------------------------------------------

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

-----------------------------------------------------
__ZNK3foo6metho dEb:
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::pair 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 __ZNSt4pairIhhE C1ERKhS2_
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
Oct 16 '05 #3
Ian
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
Oct 16 '05 #4
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
Oct 17 '05 #5
* 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.htm l#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.htm l#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?
Oct 17 '05 #6
* 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.htm l#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.htm l#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?
Oct 17 '05 #7
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.htm l#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.htm l#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
Oct 17 '05 #8
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.htm l#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.htm l#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
Oct 17 '05 #9
* 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?
Oct 17 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
2278
by: Mark McEahern | last post by:
I just wrote a very simple wrapper for the PayFlow Pro SDK (see below). A friend of mine did this before, but I didn't have access to his source, so I took it as a learning opportunity for me to write a C wrapper. I did a little searching to see whether anyone had done anything like this for Python. I didn't find anything. I did find...
8
1860
by: Raymond Hettinger | last post by:
Comments are invited on the following proposed PEP. Raymond Hettinger ------------------------------------------------------- PEP: 329
3
28182
by: Marcin Vorbrodt | last post by:
So I have a class Math that looks like this: Math { public: static Real PI(void); }; Real Math::PI(void) { return 4.0 * atan(1.0); }
10
1794
by: cppaddict | last post by:
I would like to write, within the private section of my class definition: static enum TruncType {TRUNC_TOP,TRUNC_RIGHT,TRUNC_BOTTOM,TRUNC_LEFT}; but C++ does not allow this. The four values above are constant and static, and will be used only by a private class method. I could just do:
4
2182
by: Bret Pehrson | last post by:
I just stumbled across the following problem: //.h class Masses { static double mass1; static double mass2; static double mass3; };
0
1619
by: Edson Tadeu | last post by:
I was thinking in a way to do static dispatching on enumerations, in a way similar to dispatching on integral constants using Loki's Int2Type<> or Boost.MPL's int_<>, i.e, creating types based on the enumeration constants, so I came up with this example code: #include <iostream> using namespace std; template <class EnumType>
3
5834
by: Steve Folly | last post by:
Hi, I had a problem in my code recently which turned out to be the 'the "static initialization order fiasco"' problem (<http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12>) The FAQ section describes a solution using methods returning references to static objects. But consider:
21
1474
by: google | last post by:
Hello, in embedded programming, different kinds of memory exist, e.g. RAM and ROM (Flash memory). For a class containing variables and constant values one might want to put the variables in RAM and the constants in ROM, which means that the object is split into different parts in memory. Besides from the fact that the current compiler...
2
2467
by: Ranganath | last post by:
Hi, Why is there a restriction that only integral types can be made static constant members of a class? For e.g., class B { private: static const double K = 10; };
0
7438
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7707
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7951
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
7803
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
1
5362
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5082
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3495
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1926
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1051
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.