-2

我想在 C++ 中生成具有唯一确定性名称的各种数据类型。例如:

struct struct_int_double { int mem0; double mem1; };

目前我的编译器使用计数器合成名称,这意味着在不同翻译单元中编译相同数据类型时名称不一致。

这是行不通的:

  1. 使用 ABI mangled_name 函数。因为它已经依赖于具有唯一名称的结构。通过假装结构是匿名的,可以在符合 C++11 的 ABI 中工作吗?

  2. 模板,例如 struct2,因为模板不适用于递归类型。

  3. 一个完整的修改。因为它给出的名字太长了(数百个字符!)

除了全局注册表(YUK!)之外,我唯一能想到的就是首先创建一个独特的长名称,然后使用摘要或散列函数来缩短它(希望没有冲突)。

实际问题:生成可以在类型为匿名的情况下调用的库,例如元组、求和类型、函数类型。

还有其他想法吗?

编辑:递归类型问题的补充说明。考虑定义这样的链表:

template<class T>
typedef pair<list<T>*, T> list;

这实际上是需要的。它不起作用有两个原因:首先,您不能对 typedef 进行模板化。[不,您不能使用带有 typedef 的模板类,它不起作用] 其次,您不能将 list* 作为参数传递,因为它尚未定义。在没有多态性的 C 中,您可以这样做:

struct list_int { struct list_int *next; int value; };

有几种解决方法。对于这个特定的问题,您可以使用 Barton-Nackman 技巧的变体,但它并不能一概而论。

有一个通用的解决方法,首先由 Gabrielle des Rois 向我展示,使用具有开放递归的模板,然后使用部分特化来关闭它。但这非常难以生成,即使我能弄清楚如何做到这一点,也可能无法阅读。

正确地做变体还有另一个问题,但这不是直接相关的(更糟糕的是,因为对声明具有可构造类型的联合的愚蠢限制)。

因此,我的编译器只是使用普通的 C 类型。无论如何,它必须处理多态性:编写它的原因之一是绕过包括模板在内的 C++ 类型系统的问题。这会导致命名问题。

4

2 回答 2

1

你真的需要名字来同意吗?reinterpret_cast<>只需在不同的翻译单元中以及在必要时使用不同的名称分别定义结构,以使 C++ 编译器满意。当然,这在手写代码中会很可怕,但这是由编译器生成的代码,因此您可以(我假设这样做)在生成 C++ 代码之前执行必要的静态类型检查。

如果我遗漏了什么并且您确实需要类型名称来同意,那么我认为您已经回答了您自己的问题:除非编译器可以在多个翻译单元的翻译之间共享信息(通过一些全局注册表),否则我可以'除了明显的名称修饰之外,看不到任何从类型的结构形式生成唯一的确定性名称的方法。

至于名字的长度,我不知道为什么重要?如果您正在考虑使用哈希函数来缩短名称,那么显然您不需要它们是人类可读的,那么为什么它们需要简短呢?

就我个人而言,我可能会生成半人类可读的名称,其风格与现有的名称修饰方案类似,而不用担心散列函数。因此,struct_int_double您可能会生成sid(struct, int, double) 或si32f64(struct, 32-bit integer, 64-bit float) 或其他任何东西,而不是生成。像这样的名称具有仍然可以直接解析的优点(这似乎对于调试非常重要)。

编辑

还有一些想法:

  • 模板:我看不出生成模板代码来解决这个问题有什么真正的优势,即使它是可能的。如果您担心在链接器中达到符号名称长度限制,模板将无法帮助您,因为链接器没有模板的概念:它看到的任何符号都将是 C++ 编译器生成的模板结构的错位形式,并且会与由 felix 编译器直接生成的长错名有完全相同的问题。
  • 任何已在 felix 代码中命名的类型都应保留并在生成的 C++ 代码中直接(或几乎直接)使用。我认为对于felix 代码中使用的匿名类型的复杂性存在实际(软)可读性/可维护性约束,这是您唯一需要为其生成名称的类型。我假设您的“变体”是可区分的联合体,因此每个组件部分都必须具有在 felix 代码中定义的名称(标签),并且这些名称可以再次保留。(我在评论中提到了这一点,但由于我正在编辑我的答案,我不妨将其包括在内)
  • 减少重整名称长度:通过散列函数运行长重整名称听起来是最简单的方法,只要您使用良好的散列函数并在散列名称中保留足够多的位,冲突的可能性应该是可以接受的(并且您用于编码散列名称的字母表有 37 个字符,因此完整的 160 位 sha1 散列可以写成大约 31 个字符)。散列函数的想法意味着您将无法直接从散列名称返回到原始名称,但您可能永远不需要这样做。你可以在我猜的编译过程中转储一个辅助名称映射表(或者从 C 结构定义重新生成名称,如果它可用)。或者,如果您仍然不喜欢哈希函数,您可能可以定义一个相当紧凑的位级编码(然后将其写入 37 个字符的标识符字母表中),或者甚至在该位级编码上运行一些通用压缩算法。如果您有足够的 felix 代码进行分析,您甚至可以预先生成一个固定的压缩字典。这当然是非常疯狂的事情:只需使用哈希即可。

编辑 2:对不起,脑力衰竭——sha-1 摘要是 160 位,而不是 128 位。


PS。不知道为什么这个问题被否决了——这对我来说似乎是合理的,尽管关于你正在研究的这个编译器的更多上下文可能会有所帮助。

于 2010-12-31T17:33:32.690 回答
0

我真的不明白你的问题。

template<typename T>
struct SListItem
{
    SListItem* m_prev;
    SListItem* m_next;
    T m_value;
};

int main()
{
    SListItem<int> sListItem;
}
于 2010-12-31T16:44:36.047 回答