tags:

views:

366

answers:

14

Is it possible to start an array at an index not zero...I.E. you have an array a[35], of 35 elements, now I want to index at say starting 100, so the numbers would be a[100], a[101], ... a[134], is that possible?

I'm attempting to generate a "memory map" for a board and I'll have one array called SRAM[10000] and another called BRAM[5000] for example, but in the "memory" visiblity they're contiguous, I.E. BRAM starts right after SRAM, so therefore if I try to point to memory location 11000 I would read it see that it's over 10000 then pass it to bram.

While typing this I realized I could I suppose then subtract the 10K from the number and pass that into BRAM, but for the sake of argument, is this possible to index passing 11000 to BRAM?

Thank you for any help.

Updated to fix the a[34] to a[134]

Updated for additional information: In the actual architecture I will be implementing, there can/may be a gap between the sram and bram so for example the address 11008 might not be visible in the memory map, thus writing a giant array full of memory then "partitioning" it will work, but I'll still have to do logic to determine if it's within the ranges of "sram and bram". Which is what I wanted to avoid in the first place.

+1  A: 

Not in C. You have to do the arithmetic yourself. There are probably bizarre work-arounds that work most of the time, like making a new pointer that is BRAM-11000 and using that instead.

Paul Tomblin
+8  A: 

C++ provides quite a bit more than C in this respect. You can overload operator[] to do the subtraction, and if you want report an error (e.g., throw an exception) if the subscript is out of range.

Jerry Coffin
I hope you're just pointing this out as a possible solution and not recommending it. :-) Overloading the [] operator leads to unnecessary complexity.
Steve Lazaridis
@Steve: Not really. Overloading operators to do what they normally don't is confusing. Making `a + b` write `a` and `b` to a file is confusing. `[]` is for indexing. That said, It's probably easier just to get a new pointer by adding an offset and using the built-in `operator[]`. For any more complex indexing scheme's, making a wrapper class with `operator[]` is definitely cleanest.
GMan
There's no built-in `operator[]` for classes unless you provide one.
KennyTM
@Steve:I'd say exactly the opposite: this a case of overloading the operator to do exactly what the user would expect, so it *eliminates* unnecessary complexity instead of adding it.
Jerry Coffin
+5  A: 

No — as in you can't modify the lower bound in declaration like VB6.

Yes — as in you can do tricks like

int a[35];
int* actual_a = a-100;
printf("%d", actual_a[101]);
...

because x[a] is equivalent to *(x+a). This is highly unrecommended.

KennyTM
As forming the pointer `a - 100` results in _undefined behaviour_, I would go further than just saying "highly unrecommended".
Charles Bailey
I see how storing the result is UB. But in the expression `(a-100)[101]`, would the sub-expression already cause UB? C has a lot of latitude in reordering evaluation. So, it appears the expressions `*(a-100+101)`, `*(a+101-100)` and `*(a+(101-100))` are all equal, as all can be reordered to the same result. But as the latter is not UB, it seems none should be UB. The reason I wonder is because a macro `#define ACTUAL_A (a-100)` would expand to this form.
MSalters
+10  A: 

Is it possible to start an array at an index not zero...I.E. you have an array a[35], of 35 elements, now I want to index at say starting 100, so the numbers would be a[100], a[101], ... a[134], is that possible?

No, you cannot do this in C. Arrays always start at zero. In C++, you could write your own class, say OffsetArray and overload the [] operator to access the underlying array while subtracting an offset from the index.

I'm attempting to generate a "memory map" for a board and I'll have one array called SRAM[10000] and another called BRAM[5000] for example, but in the "memory" visiblity they're contiguous, I.E. BRAM starts right after SRAM, so therefore if I try to point to memory location 11000 I would read it see that it's over 10000 then pass it to bram.

You could try something like this:

char memory[150000];
char *sram = &memory[0];
char *bram = &memory[100000];

Now, when you access sram[110000] you'll be accessing something that's "in bram"

Hans W
+1, in fact it would make sense using `memory` to access the whole memory map and `sran` and `bram` to access specific subobjects
David Rodríguez - dribeas
In general I like this idea, but I still wish for there to be that "upper bound" but I suppose that can and will be user defined.
onaclov2000
How about using a macro: `#define ARRAY_OFFSET ((x) - 100)` and accessing the array like `memory[ARRAY_OFFSET(100)]`. The macro has some delusions to it, but it is compatible with both C and C++.
Thomas Matthews
+5  A: 

You could cheat with macro:

int myarray[35];

#define a (myarray - 100)

a[100] = 0;

A pointer could also be used.

Richard Pennington
+1  A: 

The simplest way to do this:

you have:

int *array = memory ; // starts with 0;
array-= 1000 ; // now array[1000] is 0

In c++ just create class with operator[]

Artyom
That'll probably work in most C compilers but it's not guaranteed by the standard. Only pointers within an array or one past the end are guaranteed.
paxdiablo
@paxdiablo: Let's get pedantic and technical here. Does the C standard not guarantee *dereferencing* of pointers outside an array or does it not guarantee *pointer arithmetic* beyond the array boundaries? In my experience, one could define a pointer to the first UART register and adjust the pointer for other contiguous registers, even though an array was never declared.
Thomas Matthews
Pointer arithmetic is guaranteed up to _and including_ one past the end; derefering is guaranteed for the actual array elements only. The difference is so you can use pointer arithmetic to determine if you have hit the end of an array, before dereferencing the pointer. Pointers to UART registers are always UB.
MSalters
A: 

Pointers and arrays are very similar in C, so you could easilly do something like

element SRAM_MEM[10000];
element BRAM_MEM[5000];

element* SRAM = SRAM_MEM;
element* BRAM = BRAM_MEM-10000;

BRAM[10001] = 0; // sets the first element of BRAM_MEM
Chris Becke
+2  A: 
swestrup
A scary thought: the solution allows access to regions of undefined memory or it provides memory where there isn't any.
Thomas Matthews
Well, yes and no. It provides no more unrestricted access to memory than does standard array indexing in C. Provided that one doesn't index out of bounds, one is just as safe as with normal arrays.
swestrup
A: 

Just have a variable that takes into account the offset. Even if possible, having an array that doesn't start at the conventional 0 would be highly unreadable.

+5  A: 
tommieb75
+1  A: 

strictly speaking, this solution does not loet you define an array starting at an index different from 0, but you may declare your memory this way:

typedef union
{
    unsigned char all[15000];
    struct
    {
        unsigned char sram[10000];
        unsigned char bram[5000];
    };
} memory;

this does convey the intent that the memory is contiguous, and that it is split in 2 parts. note that you should beware of the alignment of bram and sram, a #pragma pack(1) may be necessary.

Adrien Plisson
A: 

Perhaps you can use union?

#pragma pack(0)
union 
{
  char array[15000];
  struct { char sram[10000]; char bram[5000];  } map;
} combination;

They are physically contiguous. If you access 'array' then it will go into either bram or sram based on the offset

You need the pragma to tell the compiler to NOT align struct members on word boundaries. This prevents a number of bytes of space between the two parts of the map structure.

Jay
+1  A: 
swestrup
A: 

A more portable solution, common to C and C++, would be to use pointers to arrays.
For example:

unsigned int Array[5000];
unsigned int * Array_Offset_100 = &Array[0] - 100; // Initializing a pointer.

According to both language standards, pointers can be incremented or decremented by a scalar value as long as the result is not outside the range of a pointer. (E.g. Decrementing a pointer with value 0 (zero) is undefined behavior.)

Thus, a pointer to the first or beginning location of an array can be changed to point to before the array, within the array and past the array. The pointer variable does not contain any information about the size of the array that it is pointing to. So a pointer can have a value representing a location before the array.

Also, according to the language standard, the pointer can have a scalar offset added to it before it is dereferenced:

unsigned int value;
value = *(Array_Offset_100 + 100);  // Add the offset to the pointer, **then** dereference.

Again, there is nothing in the standard about pointers knowing the size of the array it is pointing to (or the begin and end locations either).

Using array notation or square brackets, '[' and ']', results in an offset applied to the pointer before it is dereferenced, equivalent to the above example:

value = Array_Offset_100[100]; // Add offset, the value between '[' and ']', to pointer then dereference.

This is standard pointer arithmetic and dereferencing. Both operations are guaranteed by the standard and have no knowledge of the target array's dimensions and starting location. In fact, the pointer doesn't need to point to an array.

The validity of the dereference operation is left to the implementation (a.k.a. compiler) or the platform (OS or hardware). There are platforms that have valid data at address (location) 0x0. Many platforms will generate exceptions or signals when an attempt is made at deferencing to an invalid location (whether or not memory exists, or when the address is protected).

In summary, an array can be accessed with offsets or indices that are outside the declared range by using a pointer of the same type as an element of the array. Pointers carry no information about the range of elements it can point to. Pointers can be incremented and decremented as long as they don't go beyond the range of a pointer. The success of dereferencing a pointer ultimately depends on the platform. Compilers may add range checking to dereferencing operations.

(Please quote the sections of either C or C++ standard where pointers can't be incremented or decremented and restrictions about dereferencing when refuting this answer.)

Thomas Matthews