在C中的指针中存储小数据?

时间:2013-12-06 19:16:47

标签: c pointers casting struct void

为了保持这个简单,我有一个

的结构
typedef struct foo 
{
 void *data;
 size_t sz;
 /* various other crap */
} foo_t;

但是我发现大约90%的时间它只需要存储一个字节或者最多只需要一个字节(但有时,它需要是一大部分内存)。我要求一个令人头疼的事情来包装获取和设置函数,这些函数执行某种大小检查,只是直接在数据中存储和读取小数据而不是将其用作指针?逻辑似乎很简单,例如。

if (f->sz <= sizeof(void*) && f->sz == sizeof(char)) 
{
 return (char) f->data; 
}

从维护的角度来看,这是可行的(一方面,它使90%的结构更容易释放,并且不分配大量单个字符,上帝知道堆在哪里;另一方面,它意味着每个读写现在都有多个可能需要的代码路径,这意味着我将来会讨厌这个问题),有什么特别的原因我不能只存储一个字符(或者指针中的任何不大于sizeof(void *)的东西,稍后再读回来?我是否会在奇怪的平台上遇到端点问题或其他问题?我记得回过头来说一个CS教授说“说'指针是整数'是错误的;整数是实现指针的一种方式”但是我不知道他是否只是提出一个概念点,或者是否存在真正的存储问题编译器被告知的地点中的非地址数据是一个指针。

(我的意思是,很明显,如果我错误地使用其中一个作为指针,那会引起痛苦,但我太聪明了,不能做到这一点......对吗? 。)

3 个答案:

答案 0 :(得分:2)

如果您希望能够透明地访问它作为数据指针使用

union overlay {
  void* point;
  unsigned char array[sizeof(void*)];
};

并有一些像

这样的代码
inline
void* get_data_pointer(struct foo* f) {
  return (f->sz > sizeof(void*)) ? f->data.point : f->data.array;
};

编辑:使用这种方法,您的小类型没有处理数据布局。在任何情况下,您的其他代码都会看到void*,并根据需要将数据存储到相应的对象(并在之后以相同的方式检索它)。正如nos指出的那样,唯一可能的问题可能是您要存储的数据的对齐要求。通常,小于void*的数据类型的对齐要求将比void*更少。我不知道任何可能存在问题的平台。

BTW,POSIX保留结尾为_t的类型名称,您不应在代码中定义它们。使用类型标识符的名称与struct标记相同,没有任何错误。

typedef struct foo foo;

答案 1 :(得分:0)

您应该使用的是union,例如:

union foo {
  void *data;
  size_t sz;
  /* various other crap */
}

这是一个很好的tutorial在C中使用联盟。

答案 2 :(得分:0)

size_t是unsigned int。隐式声明,指针void的大小也等于特定编译器上int的大小。有一个名为packing的概念,默认情况下,它在gcc中是4        结构        {        char c;        int a;        } 所以s的大小是8个字节而不是5个字节,因为这三个字节不会使用这个概念与操作系统概念有关。             if(f-> sz&lt; = sizeof(void *)&amp;&amp; f-&gt; sz == sizeof(char))               {               return(char)f-&gt; data;               } 在这里你尝试做什么。 f-&gt; sz将返回存储在sz变量中的值,而sizeof(void *)将返回4.现在返回(char)f-&gt;数据这将返回地址以及如何将地址转换为char它是总是一个整数。在这里,您只返回最低有效字节。假设f-> data = 0xaabbccdd;因此,存储在最后一个最低有效字节的数据是0xdd,因此通过使用char进行类型转换,您只返回此值。 如果您有困惑,则打印printf(“%p”,f-&gt;数据),并在返回其中的位置后再次接收此值,打印该值。这里%p将以十六进制格式打印该值。可能在这里我只是检查网络如何以十六进制格式打印。我想这可能对你有所帮助 谢谢 asif aftab