2010-02-18 49 views
9

Có thể bắt đầu một mảng tại một chỉ mục không bằng không ... I.E. bạn có một mảng [35], trong 35 phần tử, bây giờ tôi muốn lập chỉ mục khi bắt đầu 100, vì vậy các con số sẽ là [100], [101], ... a [134], có khả năng không ?Chỉ mục mảng bắt đầu từ một số không 0

Tôi đang cố gắng tạo "bản đồ bộ nhớ" cho bảng và tôi sẽ có một mảng gọi là SRAM [10000] và một mảng khác được gọi là BRAM [5000], nhưng trong chế độ hiển thị "bộ nhớ", chúng tiếp giáp, IE BRAM bắt đầu ngay sau khi SRAM, do đó, nếu tôi cố gắng trỏ đến vị trí bộ nhớ 11000 tôi sẽ đọc nó thấy rằng đó là hơn 10000 sau đó vượt qua nó để bram.

Trong khi gõ này tôi nhận ra tôi có thể giả sử sau đó trừ 10K từ số và vượt qua đó vào BRAM, nhưng vì lợi ích của đối số, là điều này có thể chỉ số đi qua 11000 để BRAM?

Cảm ơn bạn đã được trợ giúp.

cập nhật để sửa chữa một [34] để a [134]

cập nhật để biết thêm thông tin: Trong kiến ​​trúc thực tế tôi sẽ được thực hiện, có thể/có thể là một khoảng cách giữa SRAM và Bram như vậy cho Ví dụ địa chỉ 11008 có thể không hiển thị trong bản đồ bộ nhớ, do đó viết một mảng khổng lồ đầy bộ nhớ rồi "phân vùng" nó sẽ hoạt động, nhưng tôi vẫn phải làm logic để xác định xem nó nằm trong phạm vi "sram và bram ". Đó là những gì tôi muốn tránh ngay từ đầu.

+1

Loại chuỗi nào là 100, 101 ... 34? : o Và không, chỉ số luôn luôn bắt đầu từ 0. bạn sẽ cần phải làm một số toán học. – GManNickG

+0

Tôi đoán [100], [101], ... [34] phải là [100], [101], ... a [134]. Ai đó có thể chỉnh sửa điều này không? –

+0

xin lỗi tôi đã bỏ lỡ 1 trong đó, tôi có nghĩa là 100, 101, ... 134 ... xin lỗi – onaclov2000

Trả lời

16

Có thể bắt đầu một mảng tại chỉ mục không bằng không ... I.E. bạn có một mảng [35], trong 35 phần tử, bây giờ tôi muốn lập chỉ mục lúc bắt đầu 100, vì vậy các con số sẽ là [100], [101], ... a [134], có khả thi không?

Không, bạn không thể thực hiện việc này trong C. Mảng luôn bắt đầu ở mức 0. Trong C++, bạn có thể viết lớp của riêng mình, nói OffsetArray và quá tải toán tử [] để truy cập mảng cơ bản trong khi trừ đi một phần bù trừ từ chỉ mục.

Tôi đang cố gắng tạo "bản đồ bộ nhớ" cho bảng và tôi sẽ có một mảng gọi là SRAM [10000] và một mảng khác gọi là BRAM [5000], nhưng trong chế độ hiển thị "bộ nhớ" chúng ' tiếp giáp, IE BRAM bắt đầu ngay sau khi SRAM, do đó, nếu tôi cố gắng trỏ đến vị trí bộ nhớ 11000 tôi sẽ đọc nó thấy rằng đó là hơn 10000 sau đó vượt qua nó để bram.

Bạn có thể thử một cái gì đó như thế này:

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

Bây giờ, khi bạn truy cập sram[110000] bạn sẽ được truy cập vào một cái gì đó "trong bram"

+2

+1, trên thực tế sẽ có ý nghĩa khi sử dụng 'bộ nhớ' để truy cập toàn bộ bản đồ bộ nhớ và' sran' và 'bram' để truy cập các subobject cụ thể –

+0

Nói chung tôi thích ý tưởng này, nhưng tôi vẫn mong muốn có được điều đó" giới hạn trên "nhưng tôi cho rằng có thể và sẽ được người dùng xác định. – onaclov2000

+2

Cách sử dụng macro: '#define ARRAY_OFFSET ((x) - 100)' và truy cập mảng như 'bộ nhớ [ARRAY_OFFSET (100)]'. Macro có một số ảo tưởng với nó, nhưng nó tương thích với cả C và C++. –

1

Không có trong C. Bạn phải tự mình làm số học. Có thể có những công việc kỳ quái làm việc hầu hết thời gian, như tạo một con trỏ mới là BRAM-11000 và sử dụng nó thay vào đó.

12

C++ cung cấp nhiều hơn một chút so với C trong khía cạnh này. Bạn có thể quá tải operator[] để thực hiện phép trừ và nếu bạn muốn báo cáo lỗi (ví dụ: ném ngoại lệ) nếu số liệu nằm ngoài phạm vi.

+1

Tôi hy vọng bạn chỉ đang chỉ ra điều này như một giải pháp có thể và không đề xuất nó. :-) Quá tải toán tử [] dẫn đến độ phức tạp không cần thiết. –

+1

@Steve: Không hẳn. Quá tải các toán tử để làm những gì họ thường không gây nhầm lẫn. Làm 'a + b' viết' a' và 'b' thành một tập tin là khó hiểu. '[]' là để lập chỉ mục. Điều đó nói rằng, có lẽ dễ dàng hơn chỉ để có được một con trỏ mới bằng cách thêm một offset và sử dụng toán tử 'built []' dựng sẵn. Đối với bất kỳ lược đồ lập chỉ mục phức tạp nào hơn, việc tạo lớp bao bọc với 'toán tử []' chắc chắn là rõ ràng nhất. – GManNickG

+0

Không có 'toán tử []' tích hợp cho các lớp trừ khi bạn cung cấp. – kennytm

6

Không - như trong bạn không thể sửa đổi giới hạn dưới trong khai báo như VB6.

Có - như trong bạn có thể làm thủ thuật như

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

x[a] tương đương với *(x+a). Điều này là rất không được khuyến nghị.

+7

Khi tạo thành con trỏ 'a - 100' kết quả trong _undefined behaviour_, tôi sẽ đi xa hơn là chỉ nói" rất không được khuyến nghị ". –

+0

Tôi thấy cách lưu trữ kết quả là UB. Nhưng trong biểu thức '(a-100) [101]', biểu thức phụ đã gây ra UB chưa? C có rất nhiều vĩ độ trong việc sắp xếp lại đánh giá. Vì vậy, nó xuất hiện các biểu thức '* (a-100 + 101)', '* (a + 101-100)' và '* (a + (101-100))' đều bằng nhau, vì tất cả có thể được sắp xếp lại cùng một kết quả. Nhưng như sau không phải là UB, có vẻ như không ai nên UB. Lý do tôi tự hỏi là vì một macro '#define ACTUAL_A (a-100)' sẽ mở rộng thành biểu mẫu này. – MSalters

7

Bạn có thể lừa gạt với vĩ mô:

int myarray[35]; 

#define a (myarray - 100) 

a[100] = 0; 

Một con trỏ cũng có thể được sử dụng.

1

Cách đơn giản nhất để làm điều này:

bạn có:

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

Trong C++ chỉ cần tạo lớp với operator[]

+1

Điều đó có thể sẽ hoạt động trong hầu hết các trình biên dịch C nhưng nó không được đảm bảo theo tiêu chuẩn. Chỉ có con trỏ trong một mảng hoặc một trong quá khứ kết thúc được đảm bảo. – paxdiablo

+0

@paxdiablo: Hãy tìm hiểu về kỹ thuật và thông tin ở đây. Liệu các tiêu chuẩn C không đảm bảo * dereferencing * của con trỏ bên ngoài một mảng hoặc không nó đảm bảo * số học con trỏ * vượt ra ngoài ranh giới mảng? Theo kinh nghiệm của tôi, người ta có thể định nghĩa một con trỏ tới thanh ghi UART đầu tiên và điều chỉnh con trỏ cho các thanh ghi tiếp giáp khác, mặc dù một mảng không bao giờ được khai báo. –

+0

Số học con trỏ được đảm bảo tối đa _ và bao gồm_ một quá khứ; derefering chỉ được đảm bảo cho các phần tử mảng thực tế. Sự khác biệt là vì vậy bạn có thể sử dụng số học con trỏ để xác định xem bạn đã nhấn vào cuối của một mảng, trước khi dereferencing con trỏ. Các con trỏ tới thanh ghi UART luôn là UB. – MSalters

0

Con trỏ và mảng rất giống trong C, vì vậy bạn easilly có thể làm một cái gì đó như

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 
4

Bạn không rõ ràng về cách bạn muốn sử dụng các mảng, nhưng cũng đủ dễ dàng để thiết lập một mảng tiếp giáp duy nhất có thể xuất hiện được hai mảng khác nhau:

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

tôi đã sử dụng & foo [xxx] ký hiệu chỉ để làm cho nó rõ ràng những gì bạn' đang làm. Dù sao, bây giờ bạn có thể sử dụng ram để chỉ mục bất cứ nơi nào vào toàn bộ mảng, hoặc sram và bram để lập chỉ mục vào các phần cụ thể.

+0

Một ý nghĩ đáng sợ: giải pháp cho phép truy cập vào các khu vực của bộ nhớ không xác định hoặc nó cung cấp bộ nhớ mà không có bất kỳ. –

+2

Vâng, vâng và không. Nó cung cấp không hạn chế truy cập vào bộ nhớ hơn so với tiêu chuẩn mảng lập chỉ mục trong C. Cung cấp rằng một trong những không chỉ ra ngoài giới hạn, một là chỉ là an toàn như với các mảng bình thường. – swestrup

0

Chỉ cần có một biến có tính đến độ lệch. Thậm chí nếu có thể, có một mảng không bắt đầu ở mức 0 thông thường sẽ rất khó đọc.

8

Tôi nhớ đọc trong cuốn sách 'Lập trình C chuyên nghiệp - Bí mật C sâu', Peter Van der Linden tiết lộ một thủ thuật để đánh lừa trình biên dịch khi suy nghĩ chênh lệch mảng bắt đầu từ 1 ... về mặt lý thuyết, thủ thuật có thể được thực hiện, tôi làm không có cuốn sách với tôi, nhưng trái tay, tôi nhớ lại đọc nó ... nó không phải là xách tay và có thể tạo ra hành vi không xác định ...

Chỉnh sửa: Xem phần 6.17 trên C-FAQ. CẢNH BÁO: Không phải hành vi Di động và Không xác định! Để báo giá từ số source tại đây.

 
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 

Hy vọng điều này sẽ hữu ích.

+0

Mặc dù đó là hành vi không xác định từ góc độ ngôn ngữ, nhưng về mặt kỹ thuật nó hoạt động một cách đáng tin cậy do cách máy tính hiện đại xử lý bộ nhớ của chúng. Mối nguy hiểm duy nhất là, trình tối ưu hóa chỉ ra rằng bạn đang gọi hành vi không xác định và tối ưu hóa mã của bạn. – cmaster

+0

Ở đâu nó nói 'kỹ thuật làm việc đáng tin cậy'? Đó là hành vi không xác định cho lý do đó một mình, tức là không được sử dụng hàng ngày, và phụ thuộc vào trình biên dịch C trong câu hỏi và cũng là môi trường riêng của mình. Không có sự đảm bảo nào, bất kể mã có tối ưu hóa hay không. Nó có thể sụp đổ, segfault, clobber một số phần bộ nhớ khác. Sử dụng mã như vậy, sẽ tăng báo động giữa những người đánh giá mã và cũng là nguyên nhân gây lo ngại - tức là mã có mùi. – t0mm13b

+0

Vâng, làm một số mã hóa lắp ráp, và bạn sẽ biết tại sao nó đáng tin cậy về mặt kỹ thuật. Con trỏ không có gì khác hơn 32 hoặc 64 bit nguyên theo mui xe, phần cứng thậm chí không phân biệt giữa ký và unsigned (vì nó không cần). Bất cứ điều gì liên quan đến số học con trỏ giống hệt với số học số nguyên không dấu. – cmaster

1

nói đúng, giải pháp này không loet bạn xác định một mảng bắt đầu từ một chỉ số khác nhau từ 0, nhưng bạn có thể tuyên bố bộ nhớ của bạn theo cách này:

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

này truyền đạt ý rằng bộ nhớ giáp và nó được chia thành 2 phần. lưu ý rằng bạn nên cẩn thận về sự liên kết của bramsram, một số #pragma pack(1) có thể cần thiết.

0

Có lẽ bạn có thể sử dụng công đoàn?

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

Chúng tiếp giáp về thể chất.Nếu bạn truy cập vào 'mảng' thì nó sẽ đi vào một trong hai mảng hoặc bram hoặc dựa trên offset

Bạn cần pragma để trình biên dịch KHÔNG căn chỉnh cấu trúc thành viên trên các ranh giới từ. Điều này ngăn cản một số byte không gian giữa hai phần của cấu trúc bản đồ.

2

Như những người khác đã lưu ý, bạn về mặt kỹ thuật có thể đạt được những gì bạn muốn bằng cách gọi con trỏ số học như thế này:

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

Trong khi điều này sẽ làm việc một cách hoàn hảo với -O0, đó là hành vi không xác định từ một quan điểm ngôn ngữ của xem. Tuy nhiên, máy hoàn toàn không phản đối điều này, với máy mà số học con trỏ liên quan giống như bất kỳ số học số nguyên không dấu nào có số uintptr_t. Do đó, nguy cơ duy nhất cho phương pháp này là trình tối ưu hóa.

Bây giờ, bạn có thể dễ dàng đánh bại trình tối ưu hóa bằng cách tách mã ở trên thành hai đơn vị biên dịch khác nhau, i. e. có một ".c" tập tin với chức năng

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

và đặt các chức năng intMalloc() thành một khác nhau ".c" file:

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

Bây giờ, bạn được an toàn, bởi vì khi tôi ưu hoa nhìn vào số học con trỏ trong fancyIntArray(), nó không biết rằng không có bộ nhớ phân bổ ở phía trước của địa chỉ mà intMalloc() trả về, vì nó không biết bất cứ điều gì về intMalloc() chính nó. Như vậy, nó buộc phải để nguyên mã của bạn. Và tất nhiên, bạn nên sử dụng các cuộc gọi trình biên dịch độc lập để biên dịch các tệp ".c" khác nhau, để trình tối ưu hóa thực sự không thể suy ra bất kỳ điều gì về số intMalloc().

+0

Chính xác thì trình tối ưu hóa có thể làm gì với mã của ví dụ đầu tiên? –

+1

@MichaelLehn Sự nguy hiểm của trình tối ưu hóa là, nó được phép * loại bỏ * mã mà nó có thể chứng minh rằng nó gọi hành vi không xác định. I E. nó có thể thay thế hành vi không xác định bằng hành vi không làm gì cả. Âm thanh thông minh, nhưng nó tạo ra khá một vài bẫy, nơi mọi người vô tình gọi hành vi không xác định - trong ví dụ đầu tiên, nó có thể chỉ cần loại bỏ toàn bộ vòng lặp. Vì vậy, nếu bạn thực sự muốn sử dụng một cái gì đó là hành vi kỹ thuật không xác định, ít nhất hãy chắc chắn rằng trình tối ưu hóa không thể suy ra những gì đang xảy ra. – cmaster

Các vấn đề liên quan