假设你不关心编译器和机器的转换风格,那么之间是否有任何明显的区别:
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
static int64_t tosigned (void *p)
{
return *(int64_t *)p;
}
int main (void)
{
int64_t i = 0xfabf00d0badf00d;
uint64_t u = 0xabad1deacafebabe;
printf("%"PRId64 "\n" "%"PRId64 "\n", tosigned(&i), tosigned(&u));
return 0;
}
这个?
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
static int64_t tosigned (void *p, int isunsigned)
{
return isunsigned ? (int64_t)*(uint64_t *)p : *(int64_t *)p;
}
int main (void)
{
int64_t i = 0xfabf00d0badf00d;
uint64_t u = 0xabad1deacafebabe;
printf("%"PRId64 "\n" "%"PRId64 "\n", tosigned(&i, 0), tosigned(&u, 1));
return 0;
}
使用clang -S -std=c99 -Wall -Wextra
-O2
及更高版本的程序集转储显示输出没有差异。但是,我想知道是否有更“正确”的方法,或者第一种方法是否会遇到未定义或特定于实现的行为。
我假设转换为指向同一类型的无符号版本的指针与投射指针取消引用的结果一样。
背景:
我正在为Lua编写一个int64库,并在进行算术的类型转换时遇到了这个学术问题。
我在Lua堆栈上存储int64_t和uint64_t userdata(存储在Lua运行时中的不透明C blob)。有一些“metamethods”分配给算术,例如,"__add"
用于x + y
而不是引发类型错误,因为你不能(通常)对非数字执行算术。但是,有符号和无符号值存储为不同的类型,因此不兼容。我对第二个参数进行了更广泛的转换,将其转换为与第一个参数相同的签名。 isunsigned
param大致匹配“这是否有一个无符号类型表?”。运行时返回存储值的void指针,以及如何转换它取决于你。
答案 0 :(得分:1)
第一种方法,即转换指针,是C标准允许的,因为C 2011(N1570)6.5 7允许通过与对象的有效类型相对应的有符号或无符号类型访问对象。也就是说,您可以访问无符号整数作为相同大小的有符号整数,反之亦然。 (应该注意,这种别名是C标准明确允许的特定情况。许多其他指针强制转换,后跟解除引用,将违反6.5 7中指定的别名规则。)
第二种方法,将整数转换为有符号整数,如果该值可在目标类型(6.3.1.3 1)中表示,而实现定义另外(并且可能陷阱),则由C标准定义(6.3.1.3 3)