Page 1 of 1

array and pointer decl's in header file

Posted: Wed Apr 09, 2008 5:45 am
by Neo
If I have a header file with contents as shown below,

Code: Select all

#ifndef __B_H__
#define __B_H__

const char *prt =" string1";

#endif
And now include the above .h in 2 separate CPP files and compile both the CPP files then I get a linkage error.
However using the following works fine,

Code: Select all

#ifndef __B_H__
#define __B_H__

const char prt[] =" string1";

#endif
Would be great if anyone could explain what is causing this?
TIA

Posted: Wed Apr 09, 2008 5:48 am
by Solar
I have a guess, but would like to see
  • the (minimal) source files used to reproduce the behaviour,
  • the exact compiler options used,
  • the exact linker error message.
Out of principle, you know. ;-)

Posted: Wed Apr 09, 2008 6:44 am
by Neo
File: b.h

Code: Select all

#ifndef __B_H__
#define __B_H__

const char *prt =" value";

#endif
File: a.cpp

Code: Select all

#include "b.h"

int main()
{
  return 0;
}
File:b.cpp

Code: Select all

#include "b.h"

int egFunc(void)
{
  return 0;
}
g++ a.cpp b.cpp
/cygdrive/c/DOCUME~1/ABCDE~1/LOCALS~1/Temp/ccCyRYxR.o:b.cpp:(.data+0x0): multiple definition of `_prt'
/cygdrive/c/DOCUME~1/ABCDE~1/LOCALS~1/Temp/cciIrrJR.o:a.cpp:(.data+0x0): first defined here
collect2: ld returned 1 exit status

Posted: Wed Apr 09, 2008 6:55 am
by JamesM
Are array declarations limited to file scope by default?

Posted: Wed Apr 09, 2008 7:10 am
by Solar
Hmmm... fun. I compiled a.cpp to a.o using either version of b.h, and objdump'ed them to find out what's up.

Code: Select all

$ objdump -t a_ptr.o

a_ptr.o:     file format pe-i386

SYMBOL TABLE:
[  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 a.cpp
File 
[  2](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _main
[  3](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x31 nreloc 2 nlnno 0
[  5](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x4 nreloc 1 nlnno 0
[  7](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[  9](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x7 nreloc 0 nlnno 0
[ 11](sec  2)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _prt
[ 12](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 ___main
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 14](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __alloca

Code: Select all

$ objdump -t a_arr.o

a_arr.o:     file format pe-i386

SYMBOL TABLE:
[  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 a.cpp
File 
[  2](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _main
[  3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 _prt
[  4](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x31 nreloc 2 nlnno 0
[  6](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[  8](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 10](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x7 nreloc 0 nlnno 0
[ 12](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 ___main
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 14](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __alloca
As for how the difference is justified, I'm clueless. Which scares be quite somewhat, as I think this is some basics I should know...

Posted: Wed Apr 09, 2008 7:30 am
by Neo
Just thinking out loud, does it have anything to do with allocation on the stack or heap?

Posted: Wed Apr 09, 2008 8:52 am
by bluecode
well, const char ptr[] creates only an initialised char array and I guess gcc/g++/ld can merge two with the same content nicely. But const char *ptr creates a const char* variable (but the variable itself is not const) pointing to the string. gcc/g++/ld can't merge them cause they are not constant.

Posted: Thu Apr 10, 2008 5:36 am
by Neo
Could this be a compiler bug by any chance?

Posted: Thu Apr 10, 2008 6:03 am
by Solar
Unlikely.

Aside from this being something very basic (and as such highly unlikely to have slipped GCC's quality checks), MSVC++ 8.0 exhibits identical behaviour.

Posted: Thu Apr 10, 2008 6:35 am
by froggey
const char *ptr = "hello"; declares a pointer to const char, equivalent to:

Code: Select all

const char some_array[6] = {'h','e','l','l','o',0};
const char *ptr = some_array;
The string "hello" gets put in rodata and the pointer is put in data and points to the string
const char array[] = "hello"; declares a fixed length array of const char:

Code: Select all

const char array[6] = {'h','e','l','l','o',0};
The array is immutable so can be put in to the rodata section and merged with identical arrays declared in other files

Posted: Thu Apr 10, 2008 1:37 pm
by bluecode
That's exactly what I said/meant, froggey 8)

Posted: Thu Apr 10, 2008 4:24 pm
by froggey
Ah, I completely missed/skimmed over your post :)

Posted: Fri Apr 11, 2008 1:10 pm
by bluecode
Well, I guess I formulated to unclear/vague...

Posted: Fri Apr 18, 2008 3:48 am
by Neo
Thanks folks.
I've been using C++ for a few years now and still am learning something new all the time. :)

Posted: Fri Apr 18, 2008 5:31 am
by Neo
Solar wrote:Hmmm... fun. I compiled a.cpp to a.o using either version of b.h, and objdump'ed them to find out what's up.

Code: Select all

$ objdump -t a_ptr.o

a_ptr.o:     file format pe-i386

SYMBOL TABLE:
[  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 a.cpp
File 
[  2](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _main
[  3](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x31 nreloc 2 nlnno 0
[  5](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x4 nreloc 1 nlnno 0
[  7](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[  9](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x7 nreloc 0 nlnno 0
[ 11](sec  2)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _prt
[ 12](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 ___main
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 14](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __alloca

Code: Select all

$ objdump -t a_arr.o

a_arr.o:     file format pe-i386

SYMBOL TABLE:
[  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 a.cpp
File 
[  2](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _main
[  3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 _prt
[  4](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x31 nreloc 2 nlnno 0
[  6](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[  8](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 10](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x7 nreloc 0 nlnno 0
[ 12](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 ___main
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 14](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __alloca
As for how the difference is justified, I'm clueless. Which scares be quite somewhat, as I think this is some basics I should know...
Just wated to confirm this.
In the first dump the ptr variable is in the .rdata section.
In the second is it in the .text section??