C语言类型转换踩坑解决过程
问题背景
开发环境:
- IDE: CCS (Code Composer Studio)
- 编译器: TI v20.12.0 STS
- ABI: COFF
- CPU: TMS320F8377D C28x
- 场景: CPU 核间通信队列
在初始化一个 CPU 核间通信的队列时,我发现队列大小的计算出现了异常。起初问题看似出现在初始化代码段,但经过抽离和调试,我发现核心问题在于计算队列大小的宏定义。
问题如下,我将出现问题的代码抽离处理调试了任然出现计算值和理想值不同,如下var1 我觉得是1,但是却为68,最终确定是size_t的问题,可是我还是不知道怎么算出来的68:
Case1
volatile uint16_t w = 0;
volatile uint16_t r = 138;struct A_t{uint16_t var[22];};
#define SIZE_XX ((1024 * 3) / sizeof(struct A_t)) //139volatile int16_t var1 = (w - r + SIZE_XX) % SIZE_XX;volatile int16_t var2 = (w - r);volatile int16_t var3 = (w - r + SIZE_XX);volatile int16_t var4 = (var2 + SIZE_XX);volatile int16_t var5 = (var2 + SIZE_XX) % SIZE_XX;volatile int16_t var6 = var3 % SIZE_XX;
在TMS320F8377D上面使用CCS调试运行可以看到变量的值为,var1 的值预期应该为1,但是实际却为68
,不符合预期:
var1 : 68
var2 : -138
var3 : 1
var4 : 1
var5 : 1
var6 : 1
但是如果我将这个队列缓存长度的宏定义改成这样就没问题了:
Case2
volatile uint16_t w = 0;
volatile uint16_t r = 138;struct A_t{uint16_t var[22];};
#define SIZE_XX ((1024 * 3) / 22) //139volatile int16_t var1 = (w - r + SIZE_XX) % SIZE_XX;volatile int16_t var2 = (w - r);volatile int16_t var3 = (w - r + SIZE_XX);volatile int16_t var4 = (var2 + SIZE_XX);volatile int16_t var5 = (var2 + SIZE_XX) % SIZE_XX;volatile int16_t var6 = var3 % SIZE_XX;
在TMS320F8377D上面使用CCS调试运行可以看到变量的值为,均符合预期:
var1 : 1
var2 : -138
var3 : 1
var4 : 1
var5 : 1
var6 : 1
即使#define SIZE_XX ((1024 * 3) / 22U)
也是符合预期的。
就是使用sizeof后就不对了,我的认知中sizeof是返回size_t类型的值,于是我将SIZE_XX改为#define SIZE_XX ((1024 * 3) / (size_t)22)
出现了Case1中的问题。
我又去看了TI的编译器中size_t的定义,两个文件中的定义均如下:
//stddef.h
#ifndef _SIZE_T_DECLARED
#define _SIZE_T_DECLARED
# ifdef __clang__
typedef __SIZE_TYPE__ __SIZE_T_TYPE__;
# endiftypedef __SIZE_T_TYPE__ size_t;
#endif
//STDIO.H
#ifndef _SIZE_T_DECLARED
#define _SIZE_T_DECLARED
#ifdef __clang__
typedef __SIZE_TYPE__ size_t;
#else
typedef __SIZE_T_TYPE__ size_t;
#endif
#endif
可是__SIZE_T_TYPE__是什么,我在《TMS320C28x Optimizing C/C++ Compiler
v20.12.0.STS》https://www.ti.com.cn/cn/lit/ug/spru514v/spru514v.pdf中只看到了__SIZE_T_TYPE__的描述为Set to the type of size_t(位于37页),但是没有找到__SIZE_T_TYPE__的具体行为和实现。
我只知道size_t是C中任何对象所能达到的最大长度,它是无符号整数。但是具体是多大不知道,手册也没写,于是我想到了通过limits.h
看看size_t的范围,如下:
/* Limit of size_t. */
#if !defined(__TMS320C28XX_CLA__)
#define SIZE_MAX UINT32_MAX
#else
#define SIZE_MAX UINT16_MAX
#endif
可以看到TI的这个编译器中size_t是32bit的无符号数,于是我将将SIZE_XX改为#define SIZE_XX ((1024 * 3) / (uint32_t)22)
出现了Case1中的问题。可是我还是无法理解问题到底出在哪里。
我知道TI的C28x的编译器中一个字节是16bit的,默认的int类型实际为int16_t,SIZE_XX 得到的结果类型为size_t->uint32_t,我按照这个来计算volatile uint32_t var3_u32 = (w - r + SIZE_XX);->var3_u32 = 65537,于是65537 Mod 139 = 68。
具体来说:
表达式 (w - r) 的类型为uint16_t,所以var2_u16为65398
表达式 (w - r + SIZE_XX) = (65398u16+139u32) = 65537u32
所以 (w - r + SIZE_XX) % SIZE_XX = 65537u32 % 139u32 = 68u32volatile uint32_t var3_u32 = (w - r + SIZE_XX);
volatile uint16_t var2_u16 = (w - r);
volatile uint16_t var3_u16 = (w - r + SIZE_XX);