开发者

Array indexing starting at a number not 0

开发者 https://www.devze.com 2022-12-20 09:04 出处:网络
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 th

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.


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"


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.

As a minimal demo, consider the following:

#include <iostream>
#include <stdexcept>

template <class T, int lower, int upper>
class array {
    T data[upper-lower];
public:
    T &operator[](int index) { 
        if (index < lower || index >= upper)
            throw std::range_error("Index out of range");
        return data[index-lower]; 
    }
    T *begin() { return data; }
    T *end() { return data + (upper-lower); }
};

int main() {
    array<int, -3, 5> data;

    for (int i=-3; i<5; i++)
        data[i] = i;

    for (auto const &i : data) 
        std::cout << i << "\t";
    std::cout << "\n";
}


I remember reading in the book 'Expert C Programming - Deep C Secrets', Peter Van der Linden discloses a trick to fool the compiler into thinking array offsets starts at 1...theoretically the trick can be accomplished, I do not have the book with me, but offhand, I recall reading it...it is not portable and may produce undefined behavior...

Edit: See here section 6.17 on the C-FAQ. WARNING: Not Portable and Undefined behavior! To quote from the source here.

6.17: Here's a neat trick: 
      if I write int realarray[10]; 
         int *array = &realarray[-1]; 
I can treat "array" as if it were a 1-based array. A: Although this technique 
is attractive (and was used in old editions of the book _Numerical Recipes in C_), 
it is not strictly conforming to the C Standard. Pointer arithmetic is defined 
only as long as the pointer points within the same allocated block of memory, 
or to the imaginary "terminating" element one past it; otherwise, the behavior 
is undefined, *even if the pointer is not dereferenced*. The code above could 
fail if, while subtracting the offset, an illegal address were generated 
(perhaps because the address tried to "wrap around" past the beginning of some 
memory segment). 

References: K&R2 Sec. 5.3 p. 100, Sec. 5.4 pp. 102-3, Sec. A7.7 pp. 205-6; 
ISO Sec. 6.3.6; Rationale Sec. 3.2.2.3.

Read more: http://www.faqs.org/faqs/C-faq/faq/#ixzz0ftyqHOvm

Hope this helps.


You could cheat with macro:

int myarray[35];

#define a (myarray - 100)

a[100] = 0;

A pointer could also be used.


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.


You're not very clear on exactly how you want to use these arrays, but its easy enough to set up a single contiguous array that can appear to be two different arrays:

int   ram[15000]; 
int * sram=&ram[0];
int * bram=&ram[10000];

I used the &foo[xxx] notation just to make it explicit what you're doing. Anyway, you can now use ram to index anywhere into the entire array, or sram and bram to index into particular parts.


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.


As others have noted, you can technically achieve what you want by invoking pointer arithmetic like this:

int* myArray = malloc((upperBound - lowerBound) * sizeof(*myArray));
myArray -= lowerBound;
...
for(int i = lowerBound; i < upperBound; i++) {
    myArray[i];
}

While this will work flawlessly with -O0, it is undefined behaviour from a language point of view. The machine, however, has absolutely no objections to this, to the machine the pointer arithmetic involved is the same as any unsigned integer arithmetic with uintptr_t. Thus, the only danger to this approach is the optimizer.

Now, you can easily defeat the optimizer by splitting the code above into two different compilation units, i. e. have one ".c" file with the function

int* fancyIntArray(size_t lowerBound, size_t upperBound) {
    return intMalloc(upperBound - lowerBound) - lowerBound;
}

and put the function intMalloc() into a different ".c" file:

int* intMalloc(size_t size) {
    return malloc(size_t*sizeof(int));
}

Now, you are safe, because when the optimizer looks at the pointer arithmetic in fancyIntArray(), it does not know that there is no allocated memory in front of the address that intMalloc() returns, as it does not know anything about intMalloc() itself. As such, it is forced to leave your code intact.

And, of course, you should use independent compiler calls to compile the different ".c" files, so that the optimizer really cannot deduce anything about intMalloc().


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.


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[]


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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消