Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/189.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C “free(一个指针)”是定义良好的还是UB?_C_Language Lawyer - Fatal编程技术网

C “free(一个指针)”是定义良好的还是UB?

C “free(一个指针)”是定义良好的还是UB?,c,language-lawyer,C,Language Lawyer,当然,分配和释放同一个指针是定义良好的 void *p1 = malloc(42); assert(p1); ... free(p1); 。。。当这些整数类型存在时,尽管不一定是相同的位模式,但通过intptr\u t/uintptpr\u t进行转换会创建一个可比较的指针(如“比较相等”C11 7.20.1.4)。可以说,p2和p3具有相同的值,但可能具有不同的表示形式 void *p2 = malloc(42); assert(p2); uintptr_t u2 = (uintptr_t)

当然,分配和释放同一个指针是定义良好的

void *p1 = malloc(42);
assert(p1);
...
free(p1);
。。。当这些整数类型存在时,尽管不一定是相同的位模式,但通过
intptr\u t/uintptpr\u t
进行转换会创建一个可比较的指针(如“比较相等”C11 7.20.1.4)。可以说,
p2
p3
具有相同的值,但可能具有不同的表示形式

void *p2 = malloc(42);
assert(p2);
uintptr_t u2 = (uintptr_t) p2;
...
void *p3 = (void *) u2;

// Specified to evaluate true C11 7.20.1.4
if (p2 == p3) ...

// Maybe true, maybe false
if (memcmp(&p2, &p3, sizeof p2) == 0) ...

// Note - early version of post had this errant code
// if (memset(&p2, &p3, sizeof p2) == 0) ...
现在通过可比较的指针转到
free()

free
函数导致
ptr
指向的空间被释放。。。如果参数与内存管理函数先前返回的指针不匹配。。。行为是未定义的。C11dr§7.22.3.3

因此,标题问题似乎要解决:
关于
免费()
“可比”是否足以“匹配”


我怀疑
free(p5)
是(UB),但不确定。没有特别的应用程序-只是尝试理解C的各个角落,没有匆忙。

类型uintptru\t保证在转换为该类型和返回后,空指针将与原始指针1相等

如果一个指针与另一个指针比较相等,则它们指向同一对象2

最后一个示例中的行为就是这样定义的,您可以使用该指针来释放对象:
free(p5)


1(引用自:ISO/IEC 9899:201x 7.20.1.4能够容纳指针的整数类型1)
以下类型使用任何有效的属性指定无符号整数类型 指向void的指针可以转换为此类型,然后再转换回指向void的指针, 结果将与原始指针进行比较: uintptr\t

2(引用自:ISO/IEC 9899:201x 6.5.9等式运算符6)
两个指针比较相等当且仅当两个指针都是空指针时,两个指针都是指向 相同的对象(包括指向对象的指针和其开头的子对象)或函数, 两者都是指向同一数组对象的最后一个元素的指针,或者一个是指针 一个指向一个数组对象的末尾,另一个指向另一个数组对象的开始的指针 恰好紧跟地址中第一个数组对象之后的数组对象
空间109)

free
不知道/不关心返回值存储在哪里,也不关心它后来转换成什么类型(它被转换回
void*
)。因此,您传入的指针并不重要,只要它指向已分配但尚未释放的内存即可

一般来说,对free的任何调用只要指向有效的堆块就可以了。当参数不完全指向有效堆块的开头时,空闲行为变得不可预测。例如,下面的代码将编译,但在执行过程中会崩溃,因为修改后的指针未指向有效的堆块:

int* pn = (int*)malloc(sizeof(int));
pn += 2;                // Now points beyond the beginning of an allocated heap block
void* pv = (void*)pn;   
free(pv);               // Therefore will crash
如果您删除pn+=2,它将再次正常。
底线:修改和强制转换指针是可以的,但是当你释放它们时,你应该确保它们指向实际分配但尚未解除分配的saomething。

有关转换到和从
uintpttr\t
转换的语言使用“比较相等”,但请注意,
void*
T*
之间的转换使用相同的短语:

指向
void
的指针可以转换为指向任何不完整或对象类型的指针,也可以转换为指向任何不完整或对象类型的指针。指向任何不完整或对象类型的指针可转换为指向
void
的指针,然后再返回;结果应与原始指针进行比较

(ISO C99标准第6.3.2.3/1节)

如果match和compare equal不是同义词,那么根据您的推理,以下内容也可以是UB:

T* p = malloc(n);
...
free(p);
而是需要:

void* p0 = malloc(n);
T* p = p0;
...
free(p0);
这违背了常识。此外,本标准和K&R第二版中的
malloc
用法示例并未进行类似操作。

参考2011年ISO C标准(C11)的最新公开草案

uintpttr\t
的定义保证指针值
p4
p5
比较相等;更简洁地说,
p4==p5
。根据6.5.9p6中指针的
==
定义,我们知道
p4
p5
指向同一个对象(因为我们已经确定
p3
的值不是空指针)

这并不保证它们具有相同的表示形式。该标准很少涉及指针的表示(除了它们有一个表示),因此
p4
p5
完全可能有不同的表示。本标准在6.2.6.1p4中明确允许:

具有相同对象表示形式的两个值(非NaN) 比较相等,但比较相等的值可能具有不同的对象 陈述

void *p2 = malloc(42);
assert(p2);
uintptr_t u2 = (uintptr_t) p2;
...
void *p3 = (void *) u2;

// Specified to evaluate true C11 7.20.1.4
if (p2 == p3) ...

// Maybe true, maybe false
if (memcmp(&p2, &p3, sizeof p2) == 0) ...

// Note - early version of post had this errant code
// if (memset(&p2, &p3, sizeof p2) == 0) ...
(这可能是也可能不是真的,取决于实施情况。)

现在的问题是,到底传递给免费的是什么

函数调用如6.5.2.2所述。第4段说:

在准备调用函数时,会计算参数, 并为每个参数指定相应参数的值 争论

(重点加上。)

因此
free()
看到的不是
p5
的对象表示(这可能不同于
p4
的对象表示),而是
p5
值,它保证与
p4
的值相同。传递该值的机制可能涉及复制对象表示,但标准所说的是传递该值,并且
free
必须处理相同值的任何不同表示
void *p4 = malloc(42);
assert(p4);
uintptr_t u4 = (uintptr_t) p4;
...
void *p5 = (void *) u4;
...
free(p5);  // UB or not UB?