其他分享
首页 > 其他分享> > c – 在C函数中创建的对象的存在

c – 在C函数中创建的对象的存在

作者:互联网

已经建立(见下文)placement new是创建对象所必需的

int* p = (int*)malloc(sizeof(int));
*p = 42;  // illegal, there isn't an int

然而,这是在C中创建对象的一种非常标准的方式.

问题是,如果在C中创建int并返回到C,那么它是否存在?

换句话说,以下是否保证合法?假设int对于C和C是相同的.

foo.h中

#ifdef __cplusplus
extern "C" {
#endif

int* foo(void);

#ifdef __cplusplus
}
#endif

foo.c的

#include "foo.h"
#include <stdlib.h>

int* foo(void) {
    return malloc(sizeof(int));
}

main.cpp中

#include "foo.h"
#include<cstdlib>

int main() {
    int* p = foo();
    *p = 42;
    std::free(p);
}

关于新安置强制性质的讨论的链接:

> Is placement new legally required for putting an int into a char array?
> https://stackoverflow.com/a/46841038/4832499
> https://groups.google.com/a/isocpp.org/forum/#!msg/std-discussion/rt2ivJnc4hg/Lr541AYgCQAJ
> https://www.reddit.com/r/cpp/comments/5fk3wn/undefined_behavior_with_reinterpret_cast/dal28n0/
> reinterpret_cast creating a trivially default-constructible object

解决方法:

我认为这个问题很糟糕.在C中我们只有翻译单元和链接的概念,后者只是意味着在不同的TU中声明的名称指向同一实体的情况.

关于链接过程本身没有任何说法,编译器/链接器必须保证其正确性;即使上面的代码片段纯粹是C源代码(malloc替换为一个漂亮的新int),结果仍然是实现定义的(例如,考虑使用不兼容的编译器选项/ ABI /运行时编译的目标文件).

因此,我们要么完全一般地谈论并得出结论,任何由多个TU构成的程序都可能是错误的,或者我们必须理所当然地认为链接过程是“有效的”(只有实现知道),因此理所当然地认为如果来自某种源语言(在本例中为C)的函数会返回一个’指向现有int的指针’,然后目标语言(C)中的相同函数必须仍然是’指向现有int的指针'(否则,在[ dcl.link],我们不能说联系已经“实现”,回到了无人区.

因此,在我看来,真正的问题是相对而言,评估C和C中“现有”int的含义.当我阅读相应的标准时,在两种语言中,int生存期基本上都是在为其保留存储时开始的:在分配(在C中)/动态(在c中)存储持续时间对象的OP情况下,这发生(在C侧)当lvalue * pointer_to_int的有效类型变为int时(例如,当它被赋值时;直到那时,not-yet-an-int可能陷阱(*)).

这种情况在OP情况下不会发生,malloc结果还没有有效类型.因此,该int既不存在于C中也不存在于C中,它只是一个重新解释的指针.

也就是说,OP代码的c部分刚刚从foo()返回后分配;如果这是预期的,那么我们可以说,鉴于C中的malloc()需要具有C语义,c侧的新位置足以使其有效(如提供的链接所示).

因此,总结一下,要么修复C代码以返回指向现有int的指针(通过赋值给它),要么通过添加placement new来修复c代码. (抱歉冗长的争论…… :))

(*)这里我并没有声称唯一的问题是存在陷阱表示;如果是的话,可以说foo()的结果是C侧的不确定值,因此你可以安全地分配给它.显然情况并非如此,因为还要考虑别名规则……

标签:object-lifetime,c-3,c,language-lawyer
来源: https://codeday.me/bug/20191005/1856415.html