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的补码算法,但这通常是一个安全的假设。