1

我正在阅读此链接如何在 C++ 中使用数组?,第 5 节。使用数组时的常见陷阱,示例如下:

// [numbers.cpp]
int numbers[42] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

// [main.cpp]
extern int* numbers;
int main()
{}

由于 numbers.cpp 中的 'numbers' 是数组的名称,它通常可以衰减为等于' &numbers[0] '的指针,我希望 main.cpp 中的 'numbers' 值仍然是 '&numbers[0]' . 但不是!相反,它是“数字[0] ”,即“1”。

或者假设我是编译器,在 'numbers.cpp' 中,我看到符号 'numbers' 作为指向 '1' 的地址,为什么在 'main.cpp' 中这个相同的符号更改为值 1 '?

我明白这就是作者所说的“类型不安全的链接”。但我不知道为什么编译器会这样做,即使编译器只是引发类型不匹配的链接错误对我来说更有意义。

注释

我想我的理解是,编译器在下面看到是等效的,以便链接器成功,否则会出现“未解决的外部”错误:

// [numbers.cpp]
int tmp[42] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //{1,..9} starts at global address 0x1234
int *numbers = &tmp[0];                    //numbers == 0x1234

// [main.cpp]
extern int* numbers;                       //numbers == 0x1234
int main()
{}

真实情况:

// [numbers.cpp]
int numbers[42] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //{1,..9} starts at global address 0x1234

// [main.cpp]
extern int* numbers;                       //numbers == numbers[0] == 1
int main()
{}
4

3 回答 3

2

以下解释方式是否有帮助:

a是数组时(即当编译器知道的类型a是数组类型时),那么语法a[i]解释为:返回数组的第i个元素。

另一方面,当a是一个指针(指向数组的第一个元素)时,相同的语法 ,a[i]被解释为:查找存储在 中的地址a,添加对应于 i 个元素的字节数,然后返回存储在那里的值。

main.cpp中,它认为那numbers是一个指针(*)并应用相应的动作。也就是说,它查找存储在 中的值numbers,将其视为地址,添加一定数量的字节并返回存储在该地址的值。

(*)它这样做是因为numbers在那里被声明为指针。编译器不知道它真的是一个数组,因为它是分开main.cpp编译的numbers.cpp(即它是一个单独的翻译单元)。所以它不会把数组衰减成一个指针——它只是假设它已经是一个指针。

于 2013-02-22T04:19:01.730 回答
1

如果 numbers 是一个数组,例如。numbers[],那么你不能改变它指向的东西。目标文件会将符号“numbers”映射到实际数组 {1, 2, ...} 但如果 numbers 是指针,例如。*numbers,然后您可以更改它指向的内容,目标文件会将符号“numbers”映射到单个指针值(它本身可能指向数组的开头,但我们不知道)。

数组和指针的作用相似,但不是一回事。

于 2013-02-22T04:01:06.617 回答
-3

在 C++ 中,典型的答案是“使用容器”。对于类似数组的容器, std::vector 通常是您想要的。如果您想要最大的性能,std::valarray 可能是一个更好的选择(当然,性能是如果您像使用它一样使用它,例如与 gslice 一起使用)。

一篇更好的文章是“我什么时候可以在 C++ 中使用 C 样式数组”。答:几乎从不,除非您必须与其他软件交互。

于 2013-02-22T04:02:23.000 回答