数组索引从数字0开始
是否有可能在索引不是零的情况下启动一个数组… IE你有一个数组a [35],35个元素,现在我想索引说起始100,所以数字将是[100],a [101],…… a [134],这可能吗?
我正在尝试为一块电路板生成一个“存储器映射”,我将有一个名为SRAM [10000]的arrays和另一个名为BRAM [5000]的arrays,但在“内存”可视性中它们是连续的,IE BRAM在SRAM之后启动,所以如果我试着指向内存位置11000,我会读它看到它超过10000然后将它传递给bram。
在输入这个时我意识到我可以假设然后从数字中减去10K并将其传递给BRAM,但是为了争论,是否可以将11000传递给BRAM?
感谢您的任何帮助。
更新以修复a [34]到[134]
更新了更多信息:在我将要实现的实际架构中,sram和bram之间可能存在差异,例如地址11008可能在内存映射中不可见,因此编写一个充满内存的巨型数组然后“分区”它将起作用,但我仍然需要做逻辑来确定它是否在“sram和bram”的范围内。 这首先是我想要避免的。
是否有可能在索引不是零的情况下启动一个数组… IE你有一个数组a [35],35个元素,现在我想索引说起始100,所以数字将是[100],a [101],…… a [134],这可能吗?
不,你不能在C中做到这一点。数组总是从零开始。 在C ++中,您可以编写自己的类,比如OffsetArray
并重载[]
运算符以访问底层数组,同时从索引中减去偏移量。
我正在尝试为一块电路板生成一个“存储器映射”,我将有一个名为SRAM [10000]的arrays和另一个名为BRAM [5000]的arrays,但在“内存”可视性中它们是连续的,IE BRAM在SRAM之后启动,所以如果我试着指向内存位置11000,我会读它看到它超过10000然后将它传递给bram。
你可以尝试这样的事情:
char memory[150000]; char *sram = &memory[0]; char *bram = &memory[100000];
现在,当您访问sram[110000]
您将访问“ bram
”中的内容
在这方面,C ++提供了比C更多的东西。 您可以重载operator[]
来进行减法,如果您想要报告错误(例如,抛出exception),如果下标超出范围。
我记得在“专家C编程 – 深C秘密”一书中读到,Peter Van der Linden公开了一个欺骗编译器思考arrays偏移从1开始的技巧……理论上可以完成这个技巧,我没有这本书和我在一起,但是随便回忆一下……它不便携,可能产生不明确的行为……
编辑:请参阅C-FAQ上的第6.17节。 警告:不可移植和未定义的行为! 从这里引用来源 。
6.17:这是一个巧妙的技巧: 如果我写int realarray [10]; int * array =&realarray [-1]; 我可以将“数组”视为基于1的数组。 答:虽然这种技术 很有吸引力(并且在C_的旧版本中使用_Numerical Recipes), 它不严格符合C标准。 指定算术是定义的 只要指针指向同一个分配的内存块, 或过去的假想的“终止”元素; 否则,行为 未定义,*即使指针未被解除引用*。 上面的代码可以 如果在减去偏移量的同时生成了非法地址,则会失败 (也许是因为地址试图“绕过”一些人的开头 记忆段)。 参考文献:K&R2 Sec。 5.3 p。 100,Sec。 5.4 pp.102-3,Sec。 A7.7 pp.205-6; ISO秒 6.3.6; 基本原理 3.2.2.3。 阅读更多:http://www.faqs.org/faqs/C-faq/faq/#ixzz0ftyqHOvm
希望这可以帮助。
你可以欺骗宏:
int myarray[35]; #define a (myarray - 100) a[100] = 0;
也可以使用指针。
不 – 因为你不能像VB6那样修改声明中的下限。
是的 – 就像你可以做的那样
int a[35]; int* actual_a = a-100; printf("%d", actual_a[101]); ...
因为x[a]
相当于*(x+a)
。 这是非常不推荐的。
你不清楚你想要如何使用这些数组,但它很容易设置一个看似两个不同数组的连续数组:
int ram[15000]; int * sram=&ram[0]; int * bram=&ram[10000];
我使用&foo [xxx]表示法只是为了明确你正在做什么。 无论如何,你现在可以使用ram来索引整个数组的任何位置,或者使用sram和bram索引到特定的部分。
严格来说,这个解决方案不会让你定义一个从不同于0的索引开始的数组,但你可以用这种方式声明你的内存:
typedef union { unsigned char all[15000]; struct { unsigned char sram[10000]; unsigned char bram[5000]; }; } memory;
这确实传达了存储器连续的意图,并且它分为两部分。 请注意,你应该注意bram
和sram
的对齐,可能需要#pragma pack(1)
。
正如其他人所指出的那样,你可以通过调用指针算法在技术上达到你想要的效果,如下所示:
int* myArray = malloc((upperBound - lowerBound) * sizeof(*myArray)); myArray -= lowerBound; ... for(int i = lowerBound; i < upperBound; i++) { myArray[i]; }
虽然这将与-O0
完美配合,但从语言的角度来看,它是未定义的行为。 然而,机器绝对没有异议,对于机器,所涉及的指针算法与使用uintptr_t
任何无符号整数运算相同。 因此,这种方法的唯一危险是优化器。
现在,您可以通过将上面的代码拆分为两个不同的编译单元来轻松地击败优化器,即具有一个带有该函数的“.c”文件
int* fancyIntArray(size_t lowerBound, size_t upperBound) { return intMalloc(upperBound - lowerBound) - lowerBound; }
并将函数intMalloc()
放入另一个 “.c”文件中:
int* intMalloc(size_t size) { return malloc(size_t*sizeof(int)); }
现在,你是安全的,因为当优化器查看fancyIntArray()
中的指针算法时,它不知道intMalloc()
返回的地址前面没有分配的内存,因为它对intMalloc()
本身。 因此,它被迫保持代码不变。
当然,您应该使用独立的编译器调用来编译不同的“.c”文件,这样优化器实际上无法推断出有关intMalloc()
任何内容。
不在C.你必须自己做算术。 大多数时候可能有奇怪的解决方法,比如制作一个新的指针BRAM-11000并使用它。
最简单的方法:
你有:
int *array = memory ; // starts with 0; array-= 1000 ; // now array[1000] is 0
在c ++中,只需使用operator[]
创建类
指针和数组在C中非常相似,所以你可以轻松地做类似的事情
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
只需要一个考虑到偏移量的变量。 即使可能,具有不以传统0开始的arrays也是非常难以理解的。
也许你可以使用联盟?
#pragma pack(0) union { char array[15000]; struct { char sram[10000]; char bram[5000]; } map; } combination;
它们在物理上是连续的。 如果您访问’array’,它将根据偏移量进入bram或sram
您需要编译指示告诉编译器不要在字边界上对齐struct成员。 这可以防止地图结构的两个部分之间存在大量字节空间。