如何判断C整数变量是否已签名?

时间:2009-09-11 17:15:25

标签: c gcc integer c-preprocessor

作为一个练习,我想写一个宏,它告诉我是否签署了整数变量。这就是我到目前为止所得到的结果,如果我在使用gcc -fsigned-char或-funsigned-char的char变量上尝试这个结果,我会得到结果。

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

这可移植吗?有没有办法在不破坏变量值的情况下做到这一点?

7 个答案:

答案 0 :(得分:5)

#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))

不破坏变量的值。但不适用于0值。

怎么样:

#define ISVARSIGNED(V) (((V)-(V)-1) < 0)

答案 1 :(得分:5)

如果您正在使用GCC,则可以使用typeof关键字来覆盖该值:

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })

这会创建一个临时变量_V,其类型与V相同。

至于便携性,我不知道。它可以在两个赞美机器上工作(也就是说,你的代码将在任何可能的情况下运行的所有东西),我相信它也适用于一个人的赞美和符号级别的机器。另请注意,如果您使用typeof,则可能需要将-1投射到typeof (V)以使其更安全(即不太可能触发警告)。

答案 2 :(得分:5)

#define ISVARSIGNED(V)  ((V)<0 || (-V)<0 || (V-1)<0)

不会改变V的值。第三个测试处理V == 0的情况。

在我的编译器(gcc / cygwin)上,这适用于intlong,但不适用于charshort

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)

也可以完成两项测试。

答案 3 :(得分:1)

这个简单的解决方案没有副作用,包括只引用v一次的好处(这在宏中很重要)。我们使用gcc扩展名“typeof”来获取v的类型,然后将-1转换为此类型:

#define IS_SIGNED_TYPE(v)   ((typeof(v))-1 <= 0)

&lt; =而不仅仅是&lt;在某些情况下(启用时)避免编译器警告。

答案 4 :(得分:1)

对所有“使其消极”答案的不同方法:

#define ISVARSIGNED(V) (~(V^V)<0)

这样就不需要为V的不同值设置特殊情况,因为∀V∈ℤ,V ^ V = 0.

答案 5 :(得分:0)

为什么你需要它作为宏?模板非常适合:

template <typename T>
bool is_signed(T) {
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>");
    return std::numeric_limits<T>::is_signed;
}

对于所有基本积分类型,它都是开箱即用的。它在编译时也会在指针上失败,只使用减法和比较的版本可能不会。

编辑:哎呀,问题需要C.但是,模板是很好的方式:P

答案 6 :(得分:-1)

有符号/无符号数学的一个显着特征是当您右移有符号数时,最高有效位被复制。当您移位无符号数时,新位为0.

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1))
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0

基本上,这个宏使用条件表达式来确定是否设置了数字的高位。如果不是,则宏通过按位否定数字来设置它。我们不能进行算术否定,因为-0 == 0.然后我们向右移1位并测试符号扩展是否发生。

这假定2的补码算法,但这通常是一个安全的假设。