【问题标题】:C Pointer QuestionC 指针问题
【发布时间】:2010-11-15 01:59:57
【问题描述】:

在我的嵌入式 c 程序中,我有一个结构:

struct var{
    unsigned long value;
    unsigned long length;

    + More
}

这些结构的数组用于保存变量。大多数存储的变量都简单地存储在“值”中,因此长度设置为 1。
但是,其中一些变量是数组,我试图将起始地址存储在“值”中。

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!

我可能会放弃并在结构中添加一个指针变量

编辑:
我想避免将指针添加到结构,因为我必须返回并重写闪存读/写函数来保存指针。这些是相当复杂的,目前工作,所以我宁愿不碰它们!

【问题讨论】:

  • 为什么 536874692 不是有效地址?
  • 刚刚意识到这一点。 536874692 是 20000EC4 这可能是有效的......
  • 请注意,如果您的“闪存读/写函数”不知道查找是指针,他们将不知道保存它指向的数据。

标签: c pointers embedded


【解决方案1】:

更简洁的选择是使用 union

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

     + More
 }

您还可以选择包含一个类型枚举,就像通常使用联合使用的片段一样。

【讨论】:

    【解决方案2】:

    可以将地址存储在value 中,方法是将其转换为unsigned long,如您所演示的。 (我认为你得到的值一个有效的地址......在十六进制中,它显示为 0x20000EC4......看起来你的嵌入式系统的数据段从 0x20000000 开始,对吧?)

    但是,将指针转换为整数(或长整数)绝不是“干净的”。为什么不添加一个

    unsigned long *starting_address;
    

    到你的结构?然后你可以避免类型转换。如果您担心这将需要更多内存,您可以使用存储 unsigned long *starting_address 或“无符号长值”的联合,这仍然比强制转换更干净。

    【讨论】:

    • 看起来 0x20000EC4 有效,谢谢。
    【解决方案3】:

    假设系统指针大小与unsigned long 的大小相同(没有保证,请使用sizeof 检查),您将使用强制转换。但这是混乱且容易出错的。考虑改用联合。

    struct var{
        unsigned short type;
        union {
            unsigned long i;
            void *p;
        } value;
        unsigned long length;
    
        + More
    }
    

    type 中存储类型的位置。

    【讨论】:

      【解决方案4】:

      我没有看到在结构中放置指针的不利之处。您是否希望内存处于连续块中?你可以这样做

      struct var
      {
         unsigned long *value;
         unsigned long length;
      
         unsigned long othervalue1;
         unsigned long othervalue2;
      };
      

      但不要忘记使用 malloc 分别为 value 分配内存。或者,如果您想使用固定数量的空间

      unsigned long value[50];
      

      【讨论】:

      • 我想避免将指针添加到结构中,因为我必须返回并重写我的闪存读/写函数来保存指针。只有值存储在闪存中,所有其他结构成员(未显示)都是手动填充的。
      【解决方案5】:

      如果你 sprintf+uart 查找会发生什么。这能给你带来什么价值?

      除非涉及转换或符号扩展,否则实际数据是相同的。 sprintf 只是对它有不同的解释。

      您只使用指针的解决方案很好。如果你真的想使用 int,你应该使用 intptr_t,它保证足够大以容纳指针。

      【讨论】:

        【解决方案6】:

        当长度为 1 时,为什么不将值设为一个长度为 1 的数组?无论如何,您不会使用更多空间。

        【讨论】:

          【解决方案7】:

          我不确定您为什么不将 value 定义为 unsigned long*。

          相反,请执行以下操作:

          struct var{
            union{
              unsigned long solo_value;
              unsigned long* multi_values;
            }
          
            unsigned long length;
            + More
          };
          

          此外,对齐规则在堆栈中的强制执行不如在堆中强。但是,如果您使用的是任何最近的编译器,它们无论如何都应该是……您可能正在用 sprintf 破坏一些东西。使用调试器或更可靠的工具提取值。

          *技术上 malloc() 等。人。执行 8 字节对齐规则,而不是语言。

          【讨论】:

            【解决方案8】:

            如前所述,您最好的选择是使用 枚举

            typedef struct var{
                 union {
                    unsigned long numeric;
                    void *ptr;  
                 } value;
                 unsigned long length;
            
                 // + More
             } composition_t;
            

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

            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;
            

            【讨论】:

              【解决方案9】:

              请记住,虽然在嵌入式系统中很可能如此,但不能保证 unsigned long 持有指针。正如其他答案所建议的那样,做标准的事情并使用工会。工会将在任何符合标准的实施中做正确的事,而不仅仅是您现在使用的。此外,它还有一个优势,就是说出你的意思,当有人没有立即理解代码(可能是你,一年后)必须处理它时,这总是很有价值的。

              【讨论】:

                【解决方案10】:

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

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

                还有一个使用 offsetof 构建的 container_of 宏(google it),它可能也很有用。

                【讨论】:

                  猜你喜欢
                  • 2011-08-02
                  • 2011-04-15
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多