独特的合成名称

时间:2010-12-31 15:43:55

标签: c++ compiler-theory

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

struct struct_int_double { int mem0; double mem1; };

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

这是不起作用的:

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

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

  3. 彻底破坏。因为它提供的名称太长(数百个字符!)

  4. 除了全局注册表(YUK!)之外,我唯一能想到的是首先创建一个唯一的长错位名称,然后使用摘要或哈希函数来缩短它(并希望没有冲突)。 / p>

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

    还有其他想法吗?

    编辑:递归类型问题的加法描述。考虑定义一个这样的链表:

    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 ++类型系统的问题。这会导致命名问题。

2 个答案:

答案 0 :(得分:1)

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

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

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

就我个人而言,我可能会生成半人类可读的名称,其风格与现有的名称修改方案类似,而且不需要使用哈希函数。因此,不是生成struct_int_double,而是生成sid(struct,int,double)或si32f64(struct,32位整数,64位浮点数)等等。这样的名称的优点是它们仍然可以直接解析(这似乎对于调试来说非常重要)。

修改

更多想法:

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

编辑2:抱歉,大脑失败 - sha-1摘要是160位,而不是128位。


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

答案 1 :(得分:0)

我真的不明白你的问题。

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

int main()
{
    SListItem<int> sListItem;
}