C指针问题

3
在我的嵌入式C程序中,我有一个结构体:
struct var{
    unsigned long value;
    unsigned long length;

    + More
}

这些结构体的数组用于保存变量。大多数存储的变量仅存储在'value'中,因此长度设置为1。
然而,其中一些变量是数组,我尝试将起始地址存储在'value'中。

unsigned long lookup[10];
variables[x].length = 10;

那么我不太确定如何存储地址...
variables[x].value = lookup;
// lookup is a pointer so I cant put it into value

或者

variables[x].value = (unsigned long)lookup;
// value reads back through sprintf+uart as '536874692'
// which couldnt be a valid memory address!

我可能会放弃并在结构中添加指针变量。
编辑: 我想避免在结构体中添加指针,因为我还需要回去重写flash读/写函数以保存指针。这些函数相当复杂,并且目前正在工作,所以我不想碰它们!

为什么 536874692 不能是一个有效的地址? - jalf
刚刚意识到,536874692是20000EC4,很可能是有效的... - Tim
请注意,如果您的“flash读/写函数”不知道lookup是一个指针,它们就不会知道要保存它所指向的数据。 - caf
10个回答

6

更清晰的选项是使用union

 struct var{
     union {
        unsigned long numeric;
        void *ptr;  
     } value;
     unsigned long length;

     + More
 }

你也可以选择包含一个类型枚举,正如通常使用union的部分一样。


5
您可以像您所示范的那样,将地址转换为unsigned long并存储在value中。(我认为您得到的值是一个有效的地址...以十六进制表示,它变成了0x20000EC4...看起来您的嵌入式系统数据段从0x20000000开始,对吗?)但是,将指针强制转换为int(或long)永远不是“干净”的。为什么不添加一个
unsigned long *starting_address;

把结构体的成员指针改为无符号长整型指针可以避免类型转换。如果你担心这样会占用更多内存,可以使用联合体来存储一个 unsigned long *starting_address 或者一个 'unsigned long value`,这比强制类型转换还要更加清晰。


看起来0x20000EC4是有效的。谢谢。 - Tim

1
假设系统指针大小与 unsigned long 相同(没有保证,请使用 sizeof 进行检查),您可以使用强制类型转换。但这样做会很混乱且容易出错。考虑改用联合体。
struct var{
    unsigned short type;
    union {
        unsigned long i;
        void *p;
    } value;
    unsigned long length;

    + More
}

你在哪里存储type类型。


0

我不认为在结构体中放置指针有什么不好的地方。你想要内存连续吗?你可以这样做:

struct var
{
   unsigned long *value;
   unsigned long length;

   unsigned long othervalue1;
   unsigned long othervalue2;
};

但是别忘了要使用malloc为值分别分配内存。或者如果你想要使用固定的空间,请使用。
unsigned long value[50];

我想避免将指针添加到结构体中,因为我必须返回并重写我的闪存读/写函数以保存指针。只有值存储在闪存中,所有其他结构成员(未显示)都是手动填充的。 - Tim

0

我不确定为什么你没有将value定义为unsigned long*。

相反,可以这样做:

struct var{
  union{
    unsigned long solo_value;
    unsigned long* multi_values;
  }

  unsigned long length;
  + More
};

此外,在堆栈中,对齐规则没有像在堆中那样严格执行。尽管如此,如果你使用任何较新的编译器,它们应该仍旧被执行。你可能正在使用 sprintf 时破坏了某些东西。用调试器或更可靠的方法提取该值。

*从技术上讲,malloc() 等函数强制执行8字节对齐规则,而不是语言本身。


0

最好的选择是使用枚举,正如已经提到的:

typedef struct var{
     union {
        unsigned long numeric;
        void *ptr;  
     } value;
     unsigned long length;

     // + More
 } composition_t;

然后使用length成员来区分数据类型:

composition_t array[2];
unsigned long lookup[10];

// Just a plain unsigned long value
array[0].value.numeric = 100;
array[0].length= 1;

// An array of 10 long values
array[0].value.ptr= lookup;
array[x].length = 10;

0
如果您使用 sprintf+uart 查找,会发生什么?那给你什么值?
除非涉及到强制类型转换或符号扩展,否则实际数据是相同的。只是由sprintf以不同的方式解释。
您使用指针的解决方案很好。如果您确实想使用int,则应使用intptr_t,它保证足够大以适应指针。

0
为什么不在长度为1时将值设为一个长度为1的数组呢?反正你也不会使用更多的空间。

0
请记住,无符号长整型并不保证可以保存一个指针,尽管在嵌入式系统中很可能如此。像其他答案建议的那样,做标准的事情并使用联合体。联合体将在任何符合标准的实现中执行正确操作,而不仅仅是当前使用的实现。此外,它具有表达你的意思的优点,在某些人必须处理代码时(例如一年后的你),这总是有价值的。

0

你知道 offsetof 吗?http://en.wikipedia.org/wiki/Offsetof

我不确定你真正想做什么,但在同一个结构体中存储一个结构体成员的地址似乎是不必要的。

还有一个 container_of 宏(谷歌一下),它使用了 offsetof,可能也会有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接