如何检查C中的指针是否属于某种类型?

时间:2009-06-04 14:31:59

标签: c gcc

如何检查指针是否属于某种类型?

使用sizeof是不够的。

我试图避免将id-number放入我的结构中来识别它们的类型。假设可能是gcc在进程中的某处放置了一个struct定义,并将定义映射到指针的已分配内存。如果这是真的,我认为会检查指针类型。

11 个答案:

答案 0 :(得分:39)

你不能。

指针只存储一个地址,并且与该地址的内容无关。

答案 1 :(得分:14)

“我正在努力避免将idnumber放入我的结构中来识别他们的类型。”不要避免这种情况。如果您确实希望能够检查类型,请将typeID作为每个结构的第一个元素。你的冲动并不坏。

答案 2 :(得分:9)

Gcc不会将结构定义放在运行时的任何位置。这意味着你不能作为标准。

它可能取决于您使用的类型信息。两个主要应用可能是:

  1. 调试或类似的运行时检查
  2. 数据结构的序列化和反序列化
  3. 在第一种情况下,信息通常可以存储在编译器输出的符号中并附加到可执行文件(在许多环境中)。

    实现是特定于平台的,通常意味着需要指示编译器输出此信息。执行此操作的程序的一个示例是gdb。仍然必须正确键入指针才能使其有用。

    对于序列化类型,通常使用您建议的值标记。但这些标签不必与内存数据一起存储。它们可以通过输出例程添加。

答案 3 :(得分:7)

指针的类型。更一般地说,C不提供内省的能力。没有编程方法来确定变量的类型。

答案 4 :(得分:5)

这里发布的所有答案都说“你做不到。”他们是对的。你不能。

但是,我甚至不敢提及它, 可以播放的游戏。这些游戏是一个糟糕的主意。我不建议在任何情况下使用它们。

比赛是什么?将牛排上的额外数据位填充到地址的未使用部分,并在使用地址的任何地方将其剥离。

因此,假设你有一个指向32字节大小的结构或类的指针。如果你确保你的内存分配与32字节地址对齐(这对于动态分配很容易,但对于堆栈的内容来说更难以保证),地址的低位将全部为0.这意味着有5个空闲位在地址的底部,足以让您放置标志,ID号,状态值等。存储空间是免费的! 即使你有一个奇怪的结构大小,几乎任何C或C ++编译器和操作系统总是将每个地址对齐到4个字节。

在64位中,您通常可以在地址的高端找到大量空闲位...很可能是16个空闲未使用的位,等待着您。这当然取决于操作系统。还有一个坏主意要考虑。你喜欢危险,不是吗?

两个缺点是:

  1. 你必须确保掩盖 在你尝试之前估价出来 取消引用指针,或传递它 任何可能尝试的事情。这使得 丑陋的代码。
  2. 你正在超越边缘跳舞 不可靠的愚蠢悬崖 危险。这就像喝酒一样 一瓶龙舌兰酒和走路磨损 在饥饿的老虎身上走钢丝。裸体。
  3. Your fate if you follow my advice
    (来源:ecoworldly.com

    有很多方法会导致错误,崩溃和痛苦。还记得我怎么说编译器将内存对齐至少4个字节?嗯,那是真的。直到找到没有的新操作系统。你是老虎食品。

    所以不要这样做。

    但是,也就是说,这确实是一种向每个地址填充类型号等额外信息的方法。您可以在every-byte-counts codeObfusicated C.

    中看到此技巧 PS:真的,我的意思是,不要这样做。即使你喜欢老虎。

答案 5 :(得分:4)

不,任何地方都没有运行时类型信息。

您应该编写函数,以便函数签名包含类型信息,并让编译器静态检查类型。例如void burp_foo(struct foo *thefoo)告诉该参数是指向struct foo的指针。由呼叫者提供一个。当然,通过类型转换,可以将任何指针提供为指向struct foo,但这是调用者的问题,而不是你的问题。

答案 6 :(得分:2)

你不能在C中做到这一点。实际上,C ++编译器会做你想要的事情(将类的类型信息存储到分配的内存中)。在C中,你没有类,只有结构,它不包含任何开销。

答案 7 :(得分:2)

避免在结构中放置 ID 成员的一种方法是使用多态,如:

typedef struct {
        char const *name;
        int id;
        /* ... */
} object_info_t;

typedef struct {
        object_info_t *info;
} object_t;

typedef struct {
        object_t object;
        int a;
} foo_t;

typedef struct {
        object_t object;
        int b;
} bar_t;

int object_get_id(object_t *object)
{
        return object->info->id;
}

请注意,您可以使用函数指针扩充object_info_t并避免完全检查id

typedef struct {
        char const *name;
        int id;
        int (*do_something)(object_t *);
} object_info_t;

int object_do_something(object_t *self)
{
        return self->info->do_something(self);
}

答案 8 :(得分:1)

C中没有这样的东西。指针既可以是特定类型,也可以是void*。没有像C ++那样的函数重载或内置运行时多态性。你可以使用函数指针来做伪面向对象的技巧,比如:


typedef void (*cmd_func)( int );
struct command
{
    int      arg;
    cmd_func action;
};

答案 9 :(得分:0)

C标准不直接允许这样做。 C ++标准具有执行此操作的能力(dynamic_casttypeid)。

typeof

GCC附带一个typeof operator,根据您正在做的事情,它可能很有用。

条件运算符

条件运算符(表达式中的问号和冒号,如x = y == 0 ? 1 : 0;has some ability to tell you if two types can be coerced into a third type(该文章是关于C ++的,但条件运算符的类型安全性在C中是相同的)。至少可以说,它的用途并不明显。

这两种技术(typeof和条件运算符)都限于编译时可用的信息。也就是说,您无法将void*传递给函数,然后使用typeof来确定指针指向该函数内部的对象的原始类型(因为此类信息在内部不可用)该函数在编译时。)


更多地考虑这一点,GTK +是用C编写的,has a system你可以考虑模仿。它们看起来像是使用类型ID,但它们不是将ID放在结构中,而是使用宏来查找内容。

答案 10 :(得分:0)

一种可能的方法是保存指针地址并递增指针以查看它的新地址。差异会给出一个提示。