c - 处理有符号整数数组,就好像它包含无符号值一样
问题描述
我继承了一些旧代码,假设 anint
可以存储从 -2 31到 2^ 31 -1 的值,溢出只是环绕,并且符号位是高位。换句话说,该代码应该使用uint32_t
,但事实并非如此。我想修复此代码以使用uint32_t
.
困难在于代码是作为源代码分发的,我不允许更改外部接口。我有一个适用于数组的函数int
。它在内部做的是自己的业务,但是int
暴露在接口中。简而言之,接口是:
struct data {
int a[10];
};
void frobnicate(struct data *param);
我想更改int a[10]
为uint32_t a[10]
,但我不允许修改 的定义struct data
。
我可以使代码在内部uint32_t
或unsigned
内部工作:
struct internal_data {
unsigned a[10];
};
void frobnicate(struct data *param) {
struct internal_data *internal = (struct internal_data *)param;
// ... work with internal ...
}
然而,这实际上不是正确的 C,因为它在指向不同类型的指针之间进行转换。
有没有办法可以添加编译时保护,这样对于那些不是“老派” 32 位的少数人来说int
,代码不会构建?如果int
小于 32 位,则代码无论如何都不会工作。对于绝大多数用户来说,代码应该构建,并且以一种告诉编译器不要做溢出int
计算的“奇怪”事情的方式。
我分发源代码,人们可以将它与他们选择的任何编译器一起使用,因此特定于编译器的技巧不相关。
我至少要补充
#if INT_MIN + 1 != -0x7fffffff
#error "This code only works with 32-bit two's complement int"
#endif
有了这个守卫,上面的演员阵容会出什么问题?有没有一种可靠的方法来操作int
数组,就像它的元素一样unsigned
,而不复制数组?
总之:
- 我无法更改函数原型。它引用了一个数组
int
。 - 代码应该将数组(不是数组的副本)作为
unsigned
. - 代码应该构建在它之前工作的平台上(至少使用足够友好的编译器),而不应该构建在它不能工作的平台上。
- 我无法控制使用哪个编译器以及使用哪些设置。
解决方案
然而,这实际上不是正确的 C,因为它在指向不同类型的指针之间进行转换。
实际上,您不能进行此类转换,因为这两种结构类型不兼容。但是,您可以使用以下解决方法:
typedef union { struct data; uint32_t array[10]; } internal_t; ... void frobnicate(struct data *param) { internal_t* internal = (internal_t*)param; ...
如果您可以更改原始结构声明但不能更改其成员名称,另一种选择是使用 C11 匿名联合:
struct data { union { int a[10]; uint32_t u32[10]; } };
这意味着用户代码访问
foo.a
不会中断。但是您需要 C11 或更高版本。或者,您可以使用 a直接
uint32_t*
访问int[10]
。这也是明确定义的,因为uint32_t
在这种情况下是有效类型的无符号等价物int
。
有没有办法可以添加编译时保护,这样对于 int 不是“老式”32 位的少数人来说,代码不会构建?
显而易见的是
static_assert(sizeof(int) == 4, "int is not 32 bits");
,但这又需要 C11。如果需要与旧 C 的向后兼容性,您可以发明一些肮脏的“穷人的静态断言”:#define stat_assert(expr) typedef int dummy_t [expr];
#if INT_MIN != -0x80000000
根据您的挑剔程度,这不是 100% 可移植的。
int
理论上可能是 64 位,但可能也不希望移植到这种虚构的系统。如果您不想拖动limits.h,您也可以将宏编写为
#if (unsigned int)-1 != 0xFFFFFFFF
无论如何,它是一个更好的宏,因为它没有任何隐藏的隐式提升宝石- 请注意,
-0x80000000
它始终 100% 等效0x80000000
于 32 位系统。
推荐阅读
- android - 是否可以在物理地板上检索物理(设备)相机高度?
- jsp - “预期语句或表达式结束”的例外
- r - 来自 R 中 quantmod 的 getSymbols() 不起作用
- r - 为什么 R HTTR 内容语句没有产生预期的请求正文?
- git - 远程服务器的 Git 客户端
- python - 列表索引必须是整数或切片而不是 str
- javascript - 尝试使用 html 中已有的 div 列表进行无限滚动
- javascript - 如果在 Django 中单击,如何使所有删除 href 标记与 java 脚本一起工作
- c++ - 条件断点失败的 GDB Eigen 调试
- reactjs - 有没有办法在单个变量下导入多个导出?