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

时间:2022-09-28 07:17:06

As an exercise, I'd like to write a macro which tells me if an integer variable is signed. This is what I have so far and I get the results I expect if I try this on a char variable with gcc -fsigned-char or -funsigned-char.

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

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

Is this portable? Is there a way to do this without destroying the value of the variable?

这是便携式吗?有没有办法在不破坏变量值的情况下执行此操作?

7 个解决方案

#1


5  

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

doesn't change the value of V. The third test handles the case where V == 0.

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

On my compiler (gcc/cygwin) this works for int and long but not for char or short.

在我的编译器(gcc / cygwin)上,这适用于int和long,但不适用于char或short。

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

also does the job in two tests.

在两次测试中也做了这项工作。

#2


5  

If you're using GCC you can use the typeof keyword to not overwrite the value:

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

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

This creates a temporary variable, _V, that has the same type as V.

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

As for portability, I don't know. It will work on a two's compliment machine (a.k.a. everything your code will ever run on in all probability), and I believe it will work on one's compliment and sign-and-magnitude machines as well. As a side note, if you use typeof, you may want to cast -1 to typeof (V) to make it safer (i.e. less likely to trigger warnings).

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

#3


5  

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

Without destroying the variable's value. But doesn't work for 0 values.

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

What about:

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

#4


1  

A different approach to all the "make it negative" answers:

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

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

That way there's no need to have special cases for different values of V, since ∀ V ∈ ℤ, V^V = 0.

这样就不需要对V的不同值有特殊情况,因为∀V∈ℤ,V ^ V = 0。

#5


1  

This simple solution has no side effects, including the benefit of only referring to v once (which is important in a macro). We use the gcc extension "typeof" to get the type of v, and then cast -1 to this type:

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

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

It's <= rather than just < to avoid compiler warnings for some cases (when enabled).

它是<=而不仅仅是 <以避免某些情况下的编译器警告(启用时)。< p>

#6


0  

Why on earth do you need it to be a macro? Templates are great for this:

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

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;
}

Which will work out-of-the-box for all fundamental integral types. It will also fail at compile-time on pointers, which the version using only subtraction and comparison probably won't.

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

EDIT: Oops, the question requires C. Still, templates are the nice way :P

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

#7


-1  

A distinguishing characteristic of signed/unsigned math is that when you right shift a signed number, the most significant bit is copied. When you shift an unsigned number, the new bits are 0.

有符号/无符号数学的一个显着特征是,当您右移有符号数时,最高有效位被复制。移位无符号数时,新位为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

So basically, this macro uses a conditional expression to determine whether the high bit of a number is set. If it's not, the macro sets it by bitwise negating the number. We can't do an arithmetic negation because -0 == 0. We then shift right by 1 bit and test whether sign extension occurred.

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

This assumes 2's complement arithmetic, but that's usually a safe assumption.

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

#1


5  

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

doesn't change the value of V. The third test handles the case where V == 0.

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

On my compiler (gcc/cygwin) this works for int and long but not for char or short.

在我的编译器(gcc / cygwin)上,这适用于int和long,但不适用于char或short。

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

also does the job in two tests.

在两次测试中也做了这项工作。

#2


5  

If you're using GCC you can use the typeof keyword to not overwrite the value:

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

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

This creates a temporary variable, _V, that has the same type as V.

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

As for portability, I don't know. It will work on a two's compliment machine (a.k.a. everything your code will ever run on in all probability), and I believe it will work on one's compliment and sign-and-magnitude machines as well. As a side note, if you use typeof, you may want to cast -1 to typeof (V) to make it safer (i.e. less likely to trigger warnings).

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

#3


5  

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

Without destroying the variable's value. But doesn't work for 0 values.

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

What about:

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

#4


1  

A different approach to all the "make it negative" answers:

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

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

That way there's no need to have special cases for different values of V, since ∀ V ∈ ℤ, V^V = 0.

这样就不需要对V的不同值有特殊情况,因为∀V∈ℤ,V ^ V = 0。

#5


1  

This simple solution has no side effects, including the benefit of only referring to v once (which is important in a macro). We use the gcc extension "typeof" to get the type of v, and then cast -1 to this type:

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

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

It's <= rather than just < to avoid compiler warnings for some cases (when enabled).

它是<=而不仅仅是 <以避免某些情况下的编译器警告(启用时)。< p>

#6


0  

Why on earth do you need it to be a macro? Templates are great for this:

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

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;
}

Which will work out-of-the-box for all fundamental integral types. It will also fail at compile-time on pointers, which the version using only subtraction and comparison probably won't.

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

EDIT: Oops, the question requires C. Still, templates are the nice way :P

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

#7


-1  

A distinguishing characteristic of signed/unsigned math is that when you right shift a signed number, the most significant bit is copied. When you shift an unsigned number, the new bits are 0.

有符号/无符号数学的一个显着特征是,当您右移有符号数时,最高有效位被复制。移位无符号数时,新位为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

So basically, this macro uses a conditional expression to determine whether the high bit of a number is set. If it's not, the macro sets it by bitwise negating the number. We can't do an arithmetic negation because -0 == 0. We then shift right by 1 bit and test whether sign extension occurred.

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

This assumes 2's complement arithmetic, but that's usually a safe assumption.

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