【问题标题】:Can declared variables within my struct be of different size我的结构中声明的变量可以具有不同的大小
【发布时间】:2012-01-13 15:05:39
【问题描述】:

我之所以问这个是因为发生了以下情况:

在标题中定义:

typedef struct PID
{
// PID parameters
uint16_t Kp; // pGain
uint16_t Ki; // iGain
uint16_t Kd; // dGain

// PID calculations OLD ONES WHERE STATICS
int24_t pTerm;
int32_t iTerm;
int32_t dTerm;
int32_t PID;

// Extra variabels
int16_t CurrentError;

// PID Time
uint16_t tick;

}_PIDObject;

在 C 源代码中:

static int16_t PIDUpdate(int16_t target, int16_t feedback)
{
      _PIDObject PID2_t;

  PID2_t.Kp = pGain2; // Has the value of 2000

      PID2_t.CurrentError = target - feedback; // Has the value of 57

      PID2_t.pTerm = PID2_t.Kp * PID2_t.CurrentError; // Should count this to (57x2000) = 114000

当我调试时发生的事情是它没有。我可以在 pGain2 中定义的最大值(种类)是 1140。1140x57 给出 64980。

不知何故,程序认为PID2_t.pTermuint16_t。但事实并非如此;它在结构中被声明为更大。

PID2_t.pTerm 以某种方式从结构中第一个声明的变量中获得了值uint16_t 或 计算有问题吗,我有一个uint16_t 乘以一个int16_t?如果我在结构之外声明它们,这将不会发生。

另外,这是我的 int def(以前从来没有问题:

#ifdef __18CXX
typedef signed char int8_t;                 // -128 -> 127               // Char & Signed Char
typedef unsigned char uint8_t;              // 0 -> 255                  // Unsigned Char
typedef signed short int int16_t;           // -32768 -> 32767           // Int
typedef unsigned short int uint16_t;        // 0 -> 65535                // Unsigned Int
typedef signed short long int int24_t;      // -8388608 -> 8388607       // Short Long
typedef unsigned short long int uint24_t;   // 0 -> 16777215             // Unsigned Short Long
typedef signed long int int32_t;            // -2147483648 -> 2147483647 // Long
typedef unsigned long int uint32_t;         // 0 -> 4294967295           // Unsigned Long
#else
#   include <stdint.h>
#endif

【问题讨论】:

  • 看起来你的 int24_t 被定义为 16 位。让我们看看typedef? :)
  • 更重要的问题:int 有多大?你能在limits.h中查看INT_MAX/UINT_MAX吗?
  • 我从未在我的项目中包含limits.h!
  • 尽管如此,int在每个平台上都有一定的宽度/精度……可以推导出来INT_MAX

标签: c struct size pic


【解决方案1】:

试试

PID2_t.pTerm = ((int24_t) PID2_t.Kp) * ((int24_t)PID2_t.CurrentError);

Joachim 的评论解释了为什么这样做。编译器在乘法之前没有将被乘数提升为int24_t,因此存在溢出。如果我们使用强制类型转换手动提升,则不会溢出。

【讨论】:

  • 不是问题,请参阅我的回答中的讨论。
  • @Kevin: ... 除非它是 16 位平台(或更奇怪的平台)。
  • @dmc:您写道:它有效。但它没有回答我的问题
  • 当我在结构中声明不同的大小时,会不会是编译器错误?
  • 我想我会解释一下,因为我显然将对话与我的 int 是 32 位的假设混淆了。证明是类型定义,它是一个 18Cxx PIC,它有 int16_t 整数。发生的情况是这两个 16 位值被提升为 int(有符号 int16,因为其中一个是)并相乘,溢出被丢弃。之后,由于分配,它们被提升为 24 位(int24_t 在这个架构上实际上是 24 位)上面的行通过在乘法之前将两个因子提升为 24 位来解决这种情况,因此不会产生任何溢出。
【解决方案2】:

我的系统没有int24_t,所以正如一些cmets所说,这是从哪里来的?

在 Joachim 的评论之后,我写了一个简短的测试:

#include <stdint.h>
#include <stdio.h>

int main() {
        uint16_t a = 2000, b = 57;
        uint16_t c = a * b;
        printf("%x\n%x\n", a*b, c);
}

输出:

1bd50
bd50

所以你得到了前 2 个字节,与 int16_t 一致。所以问题似乎是您的int24_t 定义不正确。

【讨论】:

  • 我很确定这些值在相乘之前会被提升为 int。假设是 32 位架构,结果应该是正确的,没有强制转换。
  • @JoachimIsaksson 如果您可以在 ISO 标准中找到,我将更改或删除我的答案。
  • 只找到一个草稿,在open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf第14页示例2中最清晰;在执行片段 char c1, c2; /* ... */ c1 = c1 + c2; “整数提升”要求抽象机将每个变量的值提升为整数大小,然后将两个整数相加并截断总和。
  • @JoachimIsaksson 是的,我还写了一个简短的测试程序并相应地更新了我的帖子。
  • @JoachimIsaksson:假设(32 位)似乎是错误的。 PID 广泛用于嵌入式控制系统,其中 16 位微控制器仍然很常见。所以,我猜 dmc 的回答是正确的。
【解决方案3】:

正如其他人所指出的,您的 int24_t 似乎被定义为 16 位。除了它太小之外,您通常应该小心这种类型定义。 stdint.h 将 uint_Nt 类型指定为正好 N 位。因此,假设您的处理器和编译器实际上没有 24 位数据类型,那么您就违反了标准约定。如果您最终将其定义为 32 位类型,将其命名为 uint_least24_t 会更合理,它遵循至少足够大的整数类型的模式保存 N 位。区别很重要,因为有人可能认为uint24_t 会超过 16777215。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多