我使用' malloc()'用C语言为结构分配内存。部分结构如下:
struct f2fs_sb_info {
struct f2fs_fsck *fsck;
struct f2fs_super_block *raw_super;
struct f2fs_nm_info *nm_info;
struct f2fs_sm_info *sm_info;
struct f2fs_checkpoint *ckpt;
};
我发现raw_super
的值始终为零,而ckpt
的值始终为0x40000050
。
我知道malloc()
不会初始化已分配的内存。所以分配的内存应该是随机值。但ckpt
的值始终为0x40000050
,并且每次运行程序时都不会更改。为什么呢?
答案 0 :(得分:7)
分配的内存可以在分配后存储任何值,但它不必是随机 - 分配根本不是随机生成器。
答案 1 :(得分:5)
认为这只是一个有趣的特点。
未初始化的变量(例如结构内存分配后的结构元素)可以取任何值。这样的值被称为不确定。 C标准不要求以任何方式初始化它们。请注意,读取此类变量(unsigned char
除外)的行为是 undefined ,因为未初始化的值可能是陷阱表示。
答案 2 :(得分:4)
为什么?
因为该值是不确定的。并且访问不确定的值具有未定义的行为(如果类型是由Bathsheba指出的unsigned char
则不会是UB。)
但'ckpt'的价值总是......并且不会改变
请注意,即使它到目前为止没有改变,也无法保证它永远不会改变。这种值/输出称为“垃圾”。
您是否尝试过其他编译器?这可能会改变价值。您是否尝试修改程序中不相关的部分?这可能会改变它。在运行程序时,您是否尝试过想象蝴蝶?不能保证不会改变这个值,尽管你可能需要一个思维读取适配器才能让它开心。以上都不能保证更改该值。
答案 3 :(得分:1)
程序化算法几乎总是确定性的,它们的行为总是相同的,malloc
内存选择得到了这样的算法。
malloc
通常在运行时启动时分配一些内存池,然后使用从此池中获取的内存来处理请求(如果请求是针对非常大量的内存,则可以扩大预分配内存池,或者减少如果用户释放了大量内存)。
如果在你的代码中你分配了一些内存(malloc
从池中获取),初始化它然后在使用后释放它,然后以相同的顺序再次重新分配它,你得到的概率同一块内存与之前初始化的相同数据内部非常高。这可能是你找到的原因。
您可以尝试在另一个点使用虚假分配,也许作为您的程序的第一次分配,并检查该值是否仍然相同...
无论如何,这种最终的特性必须连接到代码中的分配链,而不是系统内存,因为它使用频率更高,在分配的集合中重复临时数据的可能性非常小。
当然这是 UB ......
答案 4 :(得分:0)
虽然已经指出了很多东西,但是下面的代码表明你真的不能既不依赖于值总是相同也不总是不同。无法保证分配的内存不会被Formatter
- 值初始化,也不能保证随机化值。 0
的结果将简单地指向一个(巨大的)内存块中的地址,称为堆;在应用程序启动时,操作系统为应用程序提供堆,但不能保证操作系统总是会为您提供与应用程序堆相同的系统内存部分(可能是,但它不一定是):
考虑以下程序,其中mallocs相同的结构3 trimes
malloc
运行此程序一次的输出如下:
struct myTestStruct {
char* p1;
char* p2;
char* p3;
char* p4;
char* pToBeObserved;
};
int main()
{
struct myTestStruct *myStructs[10];
for (int i=0; i<10; i++)
myStructs[i] = (struct myTestStruct*)malloc(sizeof(myTestStruct));
for (int i=0; i<10; i++) {
printf("%d'th instance; value of pToBeObserved: %p\n", i, (void*)myStructs[i]->pToBeObserved);
}
return 0;
}
它表明,当您在同一程序执行中多次保留内存时,0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
1'th instance; value of pToBeObserved: 0x0
2'th instance; value of pToBeObserved: 0x0
3'th instance; value of pToBeObserved: 0x202020202020202
4'th instance; value of pToBeObserved: 0x7fff77dd30c8
5'th instance; value of pToBeObserved: 0x100200380
6'th instance; value of pToBeObserved: 0x0
7'th instance; value of pToBeObserved: 0x0
8'th instance; value of pToBeObserved: 0x100058568
9'th instance; value of pToBeObserved: 0xc
的值实际上会发生变化(尽管不能保证它会发生变化)。原因是,对pToBeObserved
的连续调用指向堆的不同部分,因此malloc
“查看”不同值的机会更高;
如果你反复启动程序,那么可能至少第一个pToBeObserved
将指向堆的同一部分,而可能 是操作系统为您的应用程序分配了相同的系统内存部分:
malloc
但是在任意运行中(在我的测试中运行7),值突然改变:
Run1: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
Run3: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
Run4: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
Run5: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
Run6: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
此外,如果在运行期间,我更改Run7: 0'th instance; value of pToBeObserved: 0x0
并在struct
之前添加成员,那么下一次运行总会在我的测试中产生不同的值:
pToBeObserved
此示例再次显示您只是在堆中的某个位置获取指针,如果更改结构的内存布局(通过添加成员),则成员Run1: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c
struct myTestStruct {
char added;
char* p1;
char* p2;
char* p3;
char* p4;
char* pToBeObserved;
};
Next run: 0'th instance; value of pToBeObserved: 0x6f5f687469775f6b
将查看(的不同部分)未初始化的堆内存。