[英]Type punning and malloc'ed memory
I originally asked this question: Type Punning with Unions and Heap 我最初问过这个问题: 输入Punning with Union和Heap
And not wanting the question to keep evolving to the point that anyone reading in the future had no idea what the original question was, I have a spin off question. 并且不希望这个问题不断发展,以至于任何读书的人都不知道原来的问题是什么,我有一个旋转问题。
After reading this site: https://kristerw.blogspot.com/2016/05/type-based-aliasing-in-c.html 阅读本网站后: https : //kristerw.blogspot.com/2016/05/type-based-aliasing-in-c.html
Near the bottom it talks about malloc'd memory. 在底部附近,它讨论了malloc的内存。 Is it safe to say that casting from one pointer type to another pointer type is safe when memory is on the heap?
可以说当内存在堆上时,从一种指针类型转换为另一种指针类型是安全的吗?
Example: 例:
#include <stdio.h>
#include <stdlib.h>
struct test1
{
int a;
char b;
};
struct test2
{
int c;
char d;
};
void printer(const struct test2* value);
int main()
{
struct test1* aQuickTest = malloc(sizeof(struct test1));
aQuickTest->a = 42;
aQuickTest->b = 'a';
printer((struct test2*)aQuickTest); //safe because memory was malloc'd???
return 0;
}
void printer(const struct test2* value)
{
printf("Int: %i Char: %c",value->c, value->d);
}
And guessing it might not be safe. 并猜测它可能不安全。 What would be the proper way to do this with memcpy?
用memcpy做这个的正确方法是什么? I will attempt to write an example with a function of what might hopefully work?
我将尝试编写一个具有希望功能的函数的示例?
struct test2* converter(struct test1* original);
int main()
{
struct test1* aQuickTest = malloc(sizeof(struct test1));
aQuickTest->a = 42;
aQuickTest->b = 'a';
struct test2* newStruct = converter(aQuickTest);
printer(newStruct);
return 0;
}
struct test2* converter(struct test1* original)
{
struct test2* temp;
memcpy(&temp, &original, sizeof(struct test2));
return temp;
}
void *pnt = malloc(sizeof(struct test1));
What type has the memory behind pnt pointer? pnt指针后面有什么类型的内存? No type.
没有类型。 It is uninitialized (it's value is "indeterminate").
它是未初始化的(它的价值是“不确定的”)。 There is just "memory".
只有“记忆”。
Then you do: 然后你做:
struct test1* aQuickTest = malloc(sizeof(struct test1));
You only cast the pointer. 你只投了指针。 Nothing happens here.
这里什么都没发生。 No assembly is generated.
不生成任何程序集。 Reading uninitialized memory is undefined behavior tho, so you can't read from
aQuickTest->a
(yet). 读取未初始化的内存是未定义的行为,因此您无法从
aQuickTest->a
(尚未)读取。 But you can assign: 但你可以分配:
aQuickTest->a = 1;
This writes to an object struct test1
in the memory. 这将写入内存中的对象
struct test1
。 This is assignment. 这是作业。 You can now read
aQuickTest->a
, ie. 您现在可以阅读
aQuickTest->a
,即。 print it. 打印出来。
But the following 但以下
printf("%d", ((struct test2*)aQuickTest)->a);
is undefined behavior (although it will/should work). 是未定义的行为(虽然它将/应该工作)。 You access the underlying object (ie.
struct test1
) using a not matching pointer type struct test2*
. 您使用不匹配的指针类型
struct test2*
访问底层对象(即struct test1
)。 This is called "strict alias violation". 这称为“严格别名违规”。 Dereferencing an object (ie. doing
->
or *
) using a handle of not compatible type results in undefined behavior. 使用不兼容类型的句柄取消引用对象(即,执行
->
或*
)会导致未定义的行为。 It does not matter that struct test1
and struct test2
"look the same". struct test1
和struct test2
“看起来一样”并不重要。 They are different type. 他们是不同的类型。 The rule is in C11 standard 6.5p7 .
该规则符合C11标准6.5p7 。
In the first code snipped undefined behavior happens on inside printf("Int: %i Char: %c",value->c
. The access value->
accesses the underlying memory using incompatible handle. 在第一个代码中,剪切未定义的行为发生在
printf("Int: %i Char: %c",value->c
内部printf("Int: %i Char: %c",value->c
。访问value->
使用不兼容的句柄访问底层内存。
In the second code snipped the variable temp
is only a pointer. 在剪切的第二个代码中,变量
temp
只是一个指针。 Also original
is a pointer. original
也是一个指针。 Doing memcpy(&temp, &original, sizeof(struct test2));
做
memcpy(&temp, &original, sizeof(struct test2));
is invalid, because &temp
writes into the temp
pointer and &original
writes into the original pointer. No to the memory behind pointers. As you write out of bounds into
是无效的,因为
&temp
写入temp
指针并且&original
写入original pointer. No to the memory behind pointers. As you write out of bounds into
original pointer. No to the memory behind pointers. As you write out of bounds into
original pointer. No to the memory behind pointers. As you write out of bounds into
&temp pointer and read of bounds from
&original pointer (because most probably
sizeof(temp) < sizeof(struct test2) and
sizeof(original) < sizeof(struct test2)`), undefined behavior happens. original pointer. No to the memory behind pointers. As you write out of bounds into
&temp pointer and read of bounds from
原始pointer (because most probably
pointer and read of bounds from
pointer (because most probably
sizeof(temp)<sizeof(struct test2) and
sizeof(原始)<sizeof(struct test2)`),会发生未定义的行为。
Anyway even if it were: 无论如何,即使它是:
struct test1* original = &(some valid struct test1 object).
struct test2 temp;
memcpy(&temp, original, sizeof(struct test2));
printf("%d", temp.a); // undefined behavior
accessing the memory behind temp
variable is still invalid. 访问
temp
变量后面的内存仍然无效。 As the original
didn't had struct test2
object, it is still invalid. 由于
original
没有struct test2
对象,它仍然无效。 memcpy
doesn't change the type of the object in memory. memcpy
不会更改内存中对象的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.