键入punning和malloc';记忆

键入punning和malloc';记忆,c,C,我最初问这个问题: 我不想让这个问题一直发展到将来任何一个阅读的人都不知道原来的问题是什么,我有一个附带的问题 阅读本网站后: 在底部,它谈到了malloc的记忆。当内存在堆上时,从一个指针类型转换到另一个指针类型是否安全 例如: #include <stdio.h> #include <stdlib.h> struct test1 { int a; char b; }; struct test2 { int c; char d; }

我最初问这个问题:

我不想让这个问题一直发展到将来任何一个阅读的人都不知道原来的问题是什么,我有一个附带的问题

阅读本网站后:

在底部,它谈到了malloc的记忆。当内存在堆上时,从一个指针类型转换到另一个指针类型是否安全

例如:

#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);
}
pnt指针后面的内存是什么类型的?没有类型。它未初始化(其值为“不确定”)。只有“记忆”

然后你会:

struct test1* aQuickTest = malloc(sizeof(struct test1));
你只能投下指针。这里什么也没发生。未生成任何程序集。读取未初始化的内存是未定义的行为,因此您无法从
aQuickTest->a
(尚未)读取。但您可以指定:

aQuickTest->a = 1;
这将写入内存中的对象
struct test1
。这是我的作业。您现在可以阅读
aQuickTest->a
,即打印它。
但是下面

printf("%d", ((struct test2*)aQuickTest)->a);
是未定义的行为(尽管它将/应该工作)。使用不匹配的指针类型
struct test2*
访问底层对象(即
struct test1
)。这称为“严格别名冲突”。使用not句柄取消引用对象(即执行
->
*
)会导致未定义的行为。结构测试1和结构测试2看起来相同并不重要。它们是不同类型的。这条规则是正确的

在第一个代码中,未定义的行为发生在内部
printf(“Int:%i Char:%c”,value->c
。访问
value->
使用不兼容的句柄访问底层内存

在第二段代码中,变量
temp
只是一个指针。
original
也是一个指针。Doing
memcpy(&temp,&original,sizeof(struct test2));
无效,因为
&temp
写入
temp
指针,而
&original
写入
原始指针。没有写入指针后面的内存。当您向
&temp
指针写入越界,并从
&original
指针读取边界时(因为很可能
sizeof(temp)
sizeof(original) 无论如何,即使是:

    struct test1* original = &(some valid struct test1 object).
    struct test2 temp;
    memcpy(&temp, original, sizeof(struct test2));
    printf("%d", temp.a); // undefined behavior

访问
temp
变量后面的内存仍然无效。由于
原始
没有
struct test2
对象,它仍然无效。
memcpy
不会更改内存中对象的类型。

强制转换指针类型始终是安全的。在取消引用指针时,它可能会变得未定义f存储在该位置的数据与指针类型不兼容。
可以安全地说,当内存位于堆上时,从一种指针类型转换到另一种指针类型是安全的吗?
取决于您想做什么。转换是可以的。但一旦在代码中,您使用不同的句柄访问基础对象,即
值->c
,它变得未定义。是否有任何方法可以绕过它未定义?似乎memcpy应该对此有所帮助,但我没有看到任何使用指针的示例。没有。没有。也不应该有。使用无效句柄访问内存是UB.Dot。您的
converter
函数从上到下都是无效的,当你复制指针值时,不要复制指针后面的内存。规则说,你可以使用
字符类型
访问任何内存。之所以使用
void*
类型,是因为它是一个“通用”指针,也就是说,你可以将任何指针转换成
void*
类型。目标是“传递一个指向未知对象的指针”.
1和0的实际含义是什么?
-目标是传递指针,而不是内存。指针后面可能有有效内存,也可能没有。最后,您需要将指针强制转换为兼容类型才能访问它。目标是编写统一接口API,您可以传递任何类型。因此,如果我这样做了
void*memoryPointer=malloc(sizeof(struct*test1));
然后我可以投射另一个指针
struct test1*aQuickTest=(struct test1*memoryPointer);
我可以分配一个值。
aQuickTest->a=3;
如果我执行
struct test2*newStruct=(struct test2*)memoryPointer;
我可以读取这些值,因为我实际上没有从一种定义的类型重铸到另一种类型。强制转换并不重要,访问也很重要。如果您使用
((struct test1*)memoryPointer)->a=3来初始化内存,那么您就不能使用
(struct test2*)来访问内存memoryPointer
。无论什么指针(类型?)您有障碍。访问使用的是不兼容的类型。因此,即使所有内存都正确对齐,
newStruct.c=4;
仍然无法工作?或者换句话说,除了将
void*
强制转换为
结构的
联合
以使内存正确地别名,没有其他方法可以这样做,但是我认为您关于
memcpy()
的最后一点是错误的。该函数行为的定义不取决于其参数指向的对象的类型。Re“是未定义的行为(尽管它会/应该工作)”:否。
printf("%d", ((struct test2*)aQuickTest)->a);
    struct test1* original = &(some valid struct test1 object).
    struct test2 temp;
    memcpy(&temp, original, sizeof(struct test2));
    printf("%d", temp.a); // undefined behavior