Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C++;/阿杜伊诺_C++_Struct_Arduino - Fatal编程技术网

C++ 在C++;/阿杜伊诺

C++ 在C++;/阿杜伊诺,c++,struct,arduino,C++,Struct,Arduino,我有一个结构: typedef struct { uint8_t month; // 1..12 [4 bits] uint8_t date; // 1..31 [5 bits] uint8_t hour; // 00..23 [5 bits] uint8_t minute; // 00..59 [6 bits] uint8_t second; // 00..59 [6 bits] } TimeStamp; 但是我想打包它,这样它只消耗四个字节而不是五个字节

我有一个结构:

typedef struct {
  uint8_t month;  //  1..12 [4 bits]
  uint8_t date;   //  1..31 [5 bits]
  uint8_t hour;   // 00..23 [5 bits]
  uint8_t minute; // 00..59 [6 bits]
  uint8_t second; // 00..59 [6 bits]
} TimeStamp;
但是我想打包它,这样它只消耗四个字节而不是五个字节

有没有一种方法可以通过移位来创建更紧密的结构


可能看起来不多,但它正在进入,所以在4KB页面中,保存一个字节就是额外的512字节(我也可以将剩余的额外六位用于其他内容)。

您正在查找位字段

它们看起来像这样:

typedef struct {
  uint32_t month  : 4;   // 1..12 [4 bits]
  uint32_t date   : 5;   // 1..31 [5 bits]
  uint32_t hour   : 5;   // 00..23 [5 bits]
  uint32_t minute : 6;   // 00..59 [6 bits]
  uint32_t second : 6;   // 00..59 [6 bits]
} TimeStamp;
根据编译器的不同,为了在没有填充的情况下容纳四个字节,在这种情况下,成员的大小必须为四个字节(即
uint32\t
)。否则,如果使用
uint8\t
,结构成员将被填充,使其在每个字节边界上不溢出,从而产生一个五个字节的结构。将此作为一般规则使用应有助于防止编译器差异

这里有一个MSDN链接,深入到了位字段:


通常,位字段是一种“正确”的方法,但为什么不直接存储年初以来的秒数呢?4个字节足以轻松存储这些数据;事实上,4个字节足以存储1970到2038之间的秒数。从中获取其他信息是一个简单的练习,只要您知道当前年份(只要您感兴趣的时间范围不超过70年,您可以将其与其他信息一起存储)(即使这样,您也可以将时间戳分组为68年范围,并为每个范围存储偏移量).

另一种解决方案是将值存储在一个32位变量中,并使用位移位检索单个项

uint32_t timestamp = xxxx;

uint8_t month = timestamp & 0x0F;
uint8_t date = (timestamp & 0x1F0) >> 4;
uint8_t hour = (timestamp & 0x3E00) >> 9;
uint8_t minute = (timestamp & 0xFC000) >> 14;
uint8_t second = (timestamp & 0x3F00000) >> 20;

如果你能处理两秒的精度,MS-DOS时间戳格式使用16位来保存日期(1980年为7位,月为4位,日为5位)和16位来保存时间(小时为5位,分钟为6位,秒为5位).在Arduino这样的处理器上,可能可以编写跨越16位边界分割值的代码,但我认为如果可以避免这种分割(就像MS-DOS接受两秒精度所做的那样),代码将更加高效

否则,正如在另一个答案中所指出的,使用32位秒数,因为一些基本时间通常比试图以“日历格式”跟踪事情更有效。如果您所需要做的只是从一个日历格式日期提前到下一个日历格式日期,那么执行此操作的代码可能比在日历日期和线性日期之间转换的代码要简单,但如果您需要执行其他许多操作(甚至从一个日期向后退一步到上一个日期)在输入或显示日期时,最好将日期转换为线性格式或从线性格式转换为线性格式,否则只需使用线性秒数即可

如果您选择闰年的3月1日作为基准日期,则使用线性秒数会更加方便。然后,当该日期超过1461时,从该日期中减去该日期,并在该年中添加4(16位比较和减法在Arduino上是有效的,即使在2040年,循环所需的时间也可能比单个16x16除法少)。如果日期超过364,则减去365并增加年份,最多再尝试两次[如果第三次减法后的日期是365,则保留该日期]


需要注意的是,要确保所有的角盒都能正常工作,但即使是在8位或16位的micro上,转换也会出人意料地高效。

既然您链接到了MSDN,值得一提的是,不同的编译器也可能会应用额外的限制:我的经验是,VS在更改d时会添加一个新的存储单元eclared类型,而GCC(Arduino使用)将继续将不同类型的字段打包到同一存储单元中,只要它们不溢出。始终使用相同类型当然更利于一致性。只有
无符号int
单符号int
\u Bool
的位字段才保证受所有C编译器支持(
int
也是允许的,但在位字段的上下文中,
int
可以是有符号的,也可以是无符号的,这取决于实现,因此真正使用它没有意义)。GCC支持其他类型作为扩展。
uint32\u t
可能是
无符号int
的类型定义,因此这可能是兼容的另外,对齐是未指定的,所以在这个例子中,没有最后一个位字段,可以有12个填充位。@ Sjl认为这个问题是用C++标记的,这是不相关的。在C++中,任何积分或枚举类型都是允许的:@立方也是“烧录int”。。处理器上没有足够的冷却…?@Cubic“最好是正确的,使用
unsigned int
”会更准确,但我认为SJL在这里说“explicit”是“显式选择实际正确的类型”这一想法的合理(尽管很差)解释使用一个固定大小的整数在这里甚至没有语义上的意义,因为它说:“我想要一个32位无符号整数,但让它变成4位”,这就像说“我想要一条红线,但让它变成蓝色”.像这样存储秒数的一个问题是,计算实际日期的成本很高,尤其是在嵌入式系统中,如果没有硬件分区,甚至multiplication@LưuVĩnhPhúc:如果你想做任何涉及时间的算术(例如,计算48分钟后的日期/时间),有一个转换“日历格式”的例程将线性秒转换为线性秒和将线性秒转换为日历格式可能比尝试使用日历格式进行计算更有效。如果使用2003年3月1日作为基准日期,请通过将
year
初始化为3来查找与日期
d
关联的日历日期,然后,
d
至少是1461子项动作1461,将4加到
。然后当
d
大于365时,减去365,将1…加到
。然后减去天数