【问题标题】:C --- Problems with declaration (redefinition) of global variables [duplicate]C ---全局变量的声明(重新定义)问题[重复]
【发布时间】:2019-11-07 14:57:57
【问题描述】:

所以我正在尝试编写自己的“malloc”库,但我的全局变量有问题。

在下面的代码中,您可以看到,我正在创建一个 int 指针以将整数写入 char 数组,并且该 int 指针指向我的 char 数组的第一个字节,认为它是整数的内存.

char myMemory[1048576];

int* pMem = (int*)(&myMemory[0]);
*pMem = (1048576-5);
myMemory[4] = 'f';

//... and so forth

对于最后一行,我收到以下错误消息:

redefinition of 'myMemory' with a different type 'int [4]' vs 'char [1048576]'

对于 *pMem = (...); 我得到以下内容

invalid operands to binary expression 'int*' and 'int*'

也许我不允许在全局范围内更改全局变量,当我在测试函数中执行相同的操作时一切正常。

我不可能在互联网上找到它,因为每个人都在问如何更改函数中的全局变量......

我希望有人可以帮助我,因为我认为否则我很快就会烧毁我的房子。提前谢谢你。

提姆

【问题讨论】:

  • 显示重现问题的最小完整程序。
  • 这些行是否在函数之外?
  • @Eugene Sh.是的,他们是
  • 好吧,你不能把语句放在函数之外。我认为您可能希望从一个比malloc 更简单的项目开始,因为看起来您的一般 C 知识需要提高一点。
  • 您可以对变量执行三项基本操作:defineinitializeassign。前两个可以在函数之外完成。第三个不能。但是,如果您甚至找到了初始化myMemory 的方法,它会将其从.bss 部分移动到.data,从而有效地将可执行文件的大小增加了这个数组的大小(+1MB)。

标签: c char global-variables redefinition


【解决方案1】:

快速总结:

该错误确实不适用于您尝试执行的操作 - 实施 malloc()

修复

使用不会出现redefinition of 'myMemory' with a different type 'int [4]' vs 'char [1048576]' 错误的编译器或编译器参数。

完整答案

严格来说,这段代码

int* pMem = (int*)(&myMemory[0]);

strict aliasing violation 并可能违反 C 标准的 6.3.2.3 Pointers, p7

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐引用类型,则行为未定义。

你的错误

redefinition of 'myMemory' with a different type 'int [4]' vs 'char [1048576]'

是因为你违反了严格的别名规则。

一般来说,在 C 语言中,您不能将开始时不是具有特定类型的内存视为具有另一种类型 - 除非您始终可以将任何内存视为 char 类型。例如,您不能将 char 数组视为 int 数组。

这是严格的别名规则。

但是您可以使用 int 数组并将其视为 char 数组 - 或 signed charunsigned char 数组。

即使内存确实以int 开头,但你所拥有的只是一个指向它的char 指针(或void 指针),当你将它转换回并作为int 访问它时,内存必须针对您所在的平台正确对齐。

您的代码可能会也可能不会这样做 - 在您实际运行之前您无法确定。如果它不满足对齐要求,您可能会遇到 SIGBUS 或其他一些故障 - like this.

违反任何这些规则都会导致未定义的行为。

但是

在这种情况下,您正在“尝试编写 [您的] 自己的 'malloc' 库”,而 malloc() 由实现提供,因此这些规则并不真正适用 '正在提供 C 实现本身的一部分。

为什么?为什么这些规则不适用于 C 环境本身的实现?

他们不能,因为7.22.3 Memory management functions

如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给具有基本对齐要求的任何类型对象的指针,然后用于访问分配空间中的此类对象或此类对象的数组

您根本无法在严格符合 C 代码中做到这一点。

malloc()(和calloc() 和...)管理的内存以“无类型”开始,但在符合C 代码的情况下,您不能拥有这样的“无类型”内存。使用void * 引用内存怎么样?您不能在符合 C 代码的 void * 指针上进行指针运算。而且您将不得不进行指针运算来管理内存。所以你几乎必须使用指向某种类型的指针来管理内存。

你不能使用数组来避免这种指针运算,因为这些数组也必须有一个具体的类型。

因此,您必须“键入”您在 malloc() 实现中管理的内存,但当该内存因malloc() 调用而传递给调用者时,就会违反严格的别名规则。

如果您正确管理您的记忆,您的 malloc() 实现不会违反 6.3.2.3 指针的对齐限制,第 7 页。

为什么这么多代码违反了这些规则?

因为大多数人编写代码使用的 x86 平台在访问未对齐时非常宽容

【讨论】:

  • 谢谢,这很有趣!
猜你喜欢
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 2014-01-21
相关资源
最近更新 更多