extern array question

I need to have 2 c++ files, one to have an array and the other to read it.

my question is; can you use extern to read an array? example:
main.cpp
1
2
3
4
5
6
7
8
#include <iostream>
#include <cstdlib>
using namespace std;
int main(){
extern int array1;
cout << array1[2];
string p;
cin >>p;


1
2
3
#include <iostream>
#include <cstdlib>
int array1 [] ={1, 2};
1
2
3
// extern int array1; // this declares an int

extern int array1[] ; // this declares an array of int (of an unspecified size) 
I was struggling with this very question the other day. I had a large 3 dimensional array that was to contain data I had been reading out of a file. I decided it would be cleaner to store the data in a large array within the program. Couldn't get it to work nohow. Just now, in seeing your question I tried it again, and had success with one and two dimensional arrays, but again, couldn't get three dimensional arrays to work no how. Here is a two dimensional array that works with the GNU GCC compilers ...

1
2
3
// extFile.cpp
int iNumber[2][3]={{0,1,2},{3,4,5}};
// end extFile.cpp 


1
2
3
4
5
6
7
8
9
10
11
12
//main.cpp
#include <cstdio>

extern int iNumber[2][3];

int main()
{
 printf("iNumber[1][2]= %d\n",iNumber[1][2]);
 getchar();

 return 0;
}



Before I tried that I had in in one dimensional form, and that worked fine. Just thought I'd mention that because yours looked like all you needed was a one dimensional array. Don't know if this works with the Microsoft compilers. There are differences there between that one and the GNU compilers in terms of array handling.
Last edited on
@ JLBorges: I know technically that is the answer to the OP's question but is this the correct solution for what he is trying to accomplish? I've had something similar to this issue before and I solved it with a pointer in the global scope of a shared header file that I assigned to the array I wanted. On a side note this kind of thing screams security hole to me since exporting something from your executable weakens ASLR, but that would require more research on my part to prove.
> but is this the correct solution for what he is trying to accomplish?

As far as my understanding of the language goes, yes. Not merely correct, but also apt.


> and I solved it with a pointer in the global scope of a shared header file
> that I assigned to the array I wanted.

What was the problem that you tried to solve? "A pointer in the global scope of a shared header file that I assigned to the array"?. How does one assign a pointer to an array? And why would anyone want to even try to do that?

If you have a need to insulate, then insulate - indiscriminate type-punning is not a viable alternative. It will leave you with a far bigger mess than the perceived problem that you were trying to address.


> On a side note this kind of thing screams security hole to me since exporting something from your executable weakens ASLR

I can't comprehend what that is supposed to mean either. In the issue being discussed, how does is this issue of "exporting something from your executable" become even remotely relevant?

Or, completely ignoring relevance, is "screams security hole to me since exporting something from your executable weakens ASLR" some kind of attempt to establish that shared libraries and ASLR can't coexist?
I wasn't issuing a challenge or starting an argument, I actually wanted your opinion on this.

How does one assign a pointer to an array?

I believe this is done with the assignment operator = ... I don't think I'm using the wrong term here.

The comment about ASLR has nothing to do with the issue at hand, it was a side note like I said. I thought that the OP wasn't trying to make a DLL, he was trying to link two .cpp files. I could be wrong about that to but he never out right says so one way or the other.
> I believe this is done with the assignment operator =

An array is not an assignable type.
http://coliru.stacked-crooked.com/a/1a1da2747679a55d


> I actually wanted your opinion on this.

On what?
Yes, I got tripped up on the semantics you have me there. Although I can think of a few reasons why you would want to assign a pointer to an array: http://coliru.stacked-crooked.com/a/85b4e85ee15d2e6b I actually meant that I had assigned the array to the pointer as you did on Line 5.



Ah!

A non-const pointer can be point to different things at different times, or can be null.

Other than for that, what advantage does 1 give us over 2, 3 or 4?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

static const std::size_t ARRAY_SZ = 3 ;
extern int* const pointer ; // 1

extern int array[] ; // 2

extern int (&reference_to_array)[ARRAY_SZ] ; // 3

extern int array2[ARRAY_SZ] ; // 4

int main()
{
    for( std::size_t i = 0 ; i < ARRAY_SZ ; ++i ) std::cout << pointer[i] << ' ' ; // 1
    std::cout << '\n' ;

    for( std::size_t i = 0 ; i < ARRAY_SZ ; ++i ) std::cout << array[i] << ' ' ; // 2
    std::cout << '\n' ;

    for( int v : reference_to_array ) std::cout << v << ' ' ; // 3
    std::cout << '\n' ;

    for( int v : array2 ) std::cout << v << ' ' ; // 4
    std::cout << '\n' ;
}

int array[] = { 1, 2, 3 } ;

int* const pointer = array ;

int (&reference_to_array)[3] = array ;

int array2[] = { 1, 2, 3 } ;

http://coliru.stacked-crooked.com/a/8dbf465cd4cf6e09
I have a feeling that this has to do with exporting the variables. If you just ran this code as is I know that everything in the global scope would be initialized but if you were trying to link to this as if it were a DLL or something I don't think that you'd be able to address the array directly. I could probably just look this up, but that feels like cheating.

I'm also not familiar with the syntax on Lines 20 and 23 though if that has anything to do with it.
Objects at namespace scope are initialized prior to the first statement in main.

If we need to access objects at namespace scope (which require dynamic initialization) before main is entered into, something has to be done to ensure that the dynamic initialization of the object is completed before its first use.

In a simple scenario, we have a simple solution: the construct-on-first-use idiom:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

static const std::size_t ARRAY_SZ = 8 ;

using array_type = int[ARRAY_SZ] ;

array_type& array() ;

int test = array()[3] ;

int main()
{
    for( int v : array() ) std::cout << v << ' ' ; // 4
    std::cout << '\n' << "test: " << test << '\n' ;
}

// in some translation unit

#include <random>

array_type& array()
{
     static array_type a{} ;

     // one-time initialization of a with values known only at run-time
     static std::random_device rand_dev ;
     static std::mt19937 mt( rand_dev() ) ;
     static std::uniform_int_distribution<int> distr( 100, 999 ) ;
     static int init = [&]() { for( int& v : a ) v = distr(mt) ; return 1 ; }() ;
     (void)init ; // to suppress unused variable diagnostic
     
     return a ;
}

http://coliru.stacked-crooked.com/a/42d3f18e0f881a32

For more involved situations, the solution is also more involved; typically a schwarz counter idiom is used.
See: http://www.cplusplus.com/forum/general/110827/
WOW! You really get a kick out of obfuscating you code don't you? I don't mind, it was interesting to read. It took longer then I might have liked but that's on me. I just feel sorry for the poor intern who has to upkeep your code if you actually write like this; although it is a nicely vindictive way to discourage that kind of thing I suppose so you get points for that in my book.

The range base for loop syntax was something that I must have missed when x11 rolled out, that will save some typing. Once I found some documentation on that though the rest just fell into place. Line 29 is slick, I didn't use Lambda's before because they just don't jump to the front of my brain as a solution as often as they probably could, but using them for initialization loops is inspiring. I like how compact it turns out to be. Just one follow up question about it if you don't mind; why do you return anything instead of just leaving it as a void function?
> You really get a kick out of obfuscating you code don't you?

On the contrary, I take extra care to write code in the simplest manner possible. Line 29 uses a lambda expression; but replacing short functions which have purely local context with lambda expressions is now canonical C++. There actually is nothing in those 33 lines of code that would be construed as obfuscated by a reasonably competent C++ programmer. (Well, perhaps (void)init ; on line 30, but that is why it was clarified with a comment).


> I just feel sorry for the poor intern who has to upkeep your code if you actually write like this;

Before poor interns are allowed to touch production code, they would have undergone about nine months or so of learning and mentoring; their code would have been repeatedly ripped apart during cascades of in-depth code reviews. They wouldn't have the least bit of difficulty in understanding this code.


> why do you return anything instead of just leaving it as a void function?

How can construct-on-first-use be enforced without the guarantee that the function must be called prior to the first use of the object?
they would have undergone about nine months or so of learning and mentoring

Nice, we only do 4 months of C++ training for the new hires.
> we only do 4 months of C++ training

C++ training would be for about the same period; the first six months (of which six weeks go for non-C++ stuff - communication and language skills, team building and so on).

Then they join their respective project teams, and are assigned mock real-life-like tasks. In theory, they can start working within a few weeks after that. In practice, it takes another two to four months before they become comfortable with the domain, the software architecture and the code base (large-scale infrastructure software), and are able get through a code review without too much damage for the first time. After which, they start working on the real code base.

Most organizations that I have been involved with do much, much less. The situation in India is really terrible. Almost everyone has tried to grow too fast - tried to sustain an unsustainable thirty to forty percent increase in the number of programmers, year after year. Ending up with an exclusive work-force of greenhorns who can boast of anything up to twelve years of on-the-job C++ experience.
How can construct-on-first-use be enforced without the guarantee that the function must be called prior to the first use of the object?

I was referring to the Lambda function with that question ... I can understand the idea of not making assumptions about your readers skill level but that one kind of hurt.
> I was referring to the Lambda function with that question ...

This would work equally well:
1
2
// static int init = [&]() { for( int& v : a ) v = distr(mt) ; return 1 ; }() ;
static bool init = ( [&]() { for( int& v : a ) v = distr(mt) ; }(), true ) ;


Or any construct that would cause the lambda expression to be evaluated when the function is entered into for the first time, and not be evaluated for subsequent invocations of the function.
Topic archived. No new replies allowed.