I'm trying to do bit arithmetic with variables a and b. When I reverse a, which has the value 0xAF, the result shows as 8 digits.
Unlike the others that show as 2 digits.
I don't know why it happens, but guess that it is relevant to %x's showing way and little endian?
Here is my code:
#include <stdio.h>
int main()
{
int a = 0xAF; // 10101111
int b = 0xB5; // 10110101
printf("%x \n", a & b); // a & b = 10100101
printf("%x \n", a | b); // a | b = 10111111
printf("%x \n", a ^ b); // a ^ b = 00011010
printf("%x \n", ~a); // ~a = 1....1 01010000
printf("%x \n", a << 2);// a << 2 = 1010111100
printf("%x \n", b >> 3); // b >> 3 = 00010110
return 0;
}
Considering your int a is most likely 32 bit in size, your a actually looks like this:
int a = 0xAF; // 0000 0000 0000 0000 0000 0000 1010 1111
So if you flip all the bits on that, you have
1111 1111 1111 1111 1111 1111 0101 0000
Or, in hex
0xFFFFFF50
Which is exactly what you're getting. The others show only 2 digits because trailing zeroes are omitted when printing hex, and your other bit operations do not in fact change any of the leading zeroes.
---- Credit to # chqrlie for this ----
If you really only want to see 8 bits of the result, you can do
printf("%hhx \n", ~a); // ~a = 1....1 01010000 --> Output : 50
Which restricts the printed value to unsigned char (8 bit [on modern os, not guaranteed, but very likely for your purposes]) length.
There's a lot of potential problems with code like this.
Most importantly, you should never use signed integer types like int when doing bitwise operations. Because you could either end up with unexpected results, or you could end up with undefined/implementation-defined behavior bugs if using operators like << >> on negative value integers.
So step one is to ensure you have an unsigned integer type. Preferably uint32_t or similar from stdint.h.
Another related problem is that if you use small integer types in an expression, such as uint8_t, char, short, bool etc, then they will get implicitly promoted to type int, which is a signed type. You get that even if you use unsigned char or uint8_t. This is the source of many fatal bugs related to the bitwise operators.
And finally, the printf family of functions is dangerous to use when you need to be explicit about types. While these function have literally zero type safety, they at the same time assume a certain, specific type. If you give them the wrong type you invoke undefined behavior and the program will potentially crash & burn. Also, being variable-argument list functions, they also use implicit promotion of the arguments (default argument promotions) which might also cause unforeseen bugs.
The "strange" output you experience is a combination of doing bitwise ~ on a signed type and printf expecting an unsigned int when you give it the %x conversion specifier.
In order to get more deterministic output, you could do something like this:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t a = 0xAF; // 10101111
uint32_t b = 0xB5; // 10110101
printf("%.8" PRIx32 "\n", a & b); // a & b = 10100101
printf("%.8" PRIx32 "\n", a | b); // a | b = 10111111
printf("%.8" PRIx32 "\n", a ^ b); // a ^ b = 00011010
printf("%.8" PRIx32 "\n", ~a); // ~a = 1....1 01010000
printf("%.8" PRIx32 "\n", a << 2); // a << 2 = 1010111100
printf("%.8" PRIx32 "\n", b >> 3); // b >> 3 = 00010110
return 0;
}
Related
I want to compose the number 0xAAEFCDAB from individual bytes. Everything goes well up to 4 tetrads, and for some reason extra 4 bytes are added with it. What am I doing wrong?
#include <stdio.h>
int main(void) {
unsigned long int a = 0;
a = a | ((0xAB) << 0);
printf("%lX\n", a);
a = a | ((0xCD) << 8);
printf("%lX\n", a);
a = a | ((0xEF) << 16);
printf("%lX\n", a);
a = a | ((0xAA) << 24);
printf("%lX\n", a);
return 0;
}
Output:
Constants in C are actually typed, which might not be obvious at first, and the default type for a constant is an int which is a signed 32-bit integer (it depends on the platform, but it probably is in your case).
In signed numbers, the highest bit describes the sign of the number: 1 is negative and 0 is positive (for more details you can read about two's complement).
When you perform the operation 0xAB << 24 it results in a 32-bit signed value of 0xAB000000 which is equal to 10101011 00000000 00000000 00000000 in binary. As you can see, the highest bit is set to 1, which means that the entire 32-bit signed number is actually negative.
In order to perform the | OR operation between a (which is a 64-bit unsigned number) and a 32-bit signed number, some type conversions must be performed. The size promotion is performed first, and the 32-bit signed value of 0xAB000000 is promoted to a 64-bit signed value of 0xFFFFFFFFAB000000, according to the rules of the two's complement system. This is a 64-bit signed number which has the same numerical value as the 32-bit signed one before conversion.
Afterwards, type conversion is performed from 64-bit signed to 64-bit unsigned value in order to OR the value with a. This fills the top bits with ones and results in the value you see on the screen.
In order to force your constants to be different type than 32-bit signed int you may use suffixes such as u and l, as shown in the website I linked in the beginning of my answer. In your case, a ul suffix should work best, indicating a 64-bit unsigned value. Your lines of code which OR constants with your a variable would then look similarly to this:
a = a | ((0xAAul) << 24);
Alternatively, if you want to limit yourself to 4 bytes only, a 32-bit unsigned int is enough to hold them. In that case, I suggest you change your a variable type to unsigned int and use the u suffix for your constants. Do not forget to change the printf formats to reflect the type change. The resulting code looks like this:
#include <stdio.h>
int main(void) {
unsigned int a = 0;
a = a | ((0xABu) << 0);
printf("%X\n", a);
a = a | ((0xCDu) << 8);
printf("%X\n", a);
a = a | ((0xEFu) << 16);
printf("%X\n", a);
a = a | ((0xAAu) << 24);
printf("%X\n", a);
return 0;
}
My last suggestion is to not use the default int and long types when portability and size in bits are important to you. These types are not guaranteed to have the same amount of bits on all platforms. Instead use types defined in the <stdint.h> header file, in your case probably either a uint64_t or uint32_t. These two are guaranteed to be unsigned integers (their signed counterparts omit the 'u': int64_t and int32_t) while being 64-bit and 32-bit in size respectively on all platforms. For Pros and Cons of using them instead of traditional int and long types I refer you to this Stack Overflow answer.
a = a | ((0xAA) << 24);
((0xAA) << 24) is a negative number (it is int), then it is sign extended to the size of 'unsigned long' which adds those 0xffffffff at the beginning.
You need to tell the compiler that you want an unsigned number.
a = a | ((0xAAU) << 24);
int main(void) {
unsigned long int a = 0;
a = a | ((0xAB) << 0);
printf("%lX\n", a);
a = a | ((0xCD) << 8);
printf("%lX\n", a);
a = a | ((0xEF) << 16);
printf("%lX\n", a);
a = a | ((0xAAUL) << 24);
printf("%lX\n", a);
printf("%d\n", ((0xAA) << 24));
return 0;
}
https://gcc.godbolt.org/z/fjv19bKGc
0xAA gets treated as a signed value when it is scaled up during the bit shifting. Since its high bit is 1 (0xAA = 10101010b), the scaled value is sign extended to 0x...FFFFFFAA before you shift and OR it to a.
You need to cast 0xAA to an unsigned value before bit shifting it, so it gets zero extended instead.
x is an int,
I should be able to get the correct result when 0 is not involved. In attempts to account for the 0 case, I added "& x", which I believe now should return that a number is positive iff x > 0 and x is not 0 (because in c, any number other than 0 evaluates to true, correct?)
But, when running my tests, it says it has failed to evaulate 0x7fffffff as positive and I am not sure why!
Here is my code:
int mask = 0x1;
x = x >> 31;
int lsb = mask & x;
return ( (lsb) ^ 0x1) & (x) )
Edit: I have solved the problem by changing the code to the one below! Feedback is still very much appreciated, or any problems you may spot.
int mask = 0x1;
int lsb = (x >> 31) & mask;
int result = !(lsb ^ 0x1);
return !(result | !x);
If you know the representation is 2's complement, then you can do:
#include <stdio.h>
#define IS_NEG(a) (!!((1 << 31) & (a)))
int main(void)
{
int n;
while(1) {
scanf("%d", &n);
printf("negative: %d\n", IS_NEG(n));
}
return 0;
}
Explanation:
(1 << 31) will take the number 1 and shift it 31 times to the left, thus giving you 1000 0000 0000 0000 0000 0000 0000 0000. If you don't want to use the shift, you could use 0x80000000 too.
& (a) does a bitwise test with that big binary number. Since an AND operation only returns TRUE when both operands are TRUE, it follows that only if your number is negative (in 2's complement representation) that this will return TRUE.
!!(...) This double negation accounts for the fact that when you do that bitwise AND, the returned value by the expression will be (1 << 31) if the number is really negative. So we invert it (giving us zero), than invert it again (giving us 1). Therefore, this ensures that we get a ZERO or a ONE as a final result.
IS_NEG will return 0 on positive numbers AND 0, and returns 1 on all negative numbers.
Since the MSB will be a one when the number is negative, just test that bit. Note that this will only work for 32 bit integers (so you have to check that with a sizeof(int). The example returns 1 if a number is negative, but should be no problem reworking it to return 1 for positive numbers.
Let me know if this doesn't solve the problem. As I understand, you just want to test if any given int is positive/negative.
Edit: From the comments, I made a program to help you see what's going on.
#include <stdio.h>
#define IS_NEG(a) (!!(0x80000000 & (a)))
char buf[65];
/* converts an integer #n to binary represention of #bits bits */
char *bin(int n, unsigned int bits)
{
char *s = buf;
for(bits = (1 << (bits - 1)); bits > 0; bits = bits >> 1)
/* look! double negation again! Why this? :) */
*s++ = !!(n & bits) + 48;
*s = 0;
return buf;
}
int main(void)
{
/* R will be our partial result through-out the loop */
int r, n;
while(1) {
/* get the number */
scanf("%d", &n);
/* this is the inner part of the macro
* after this, we could say IS_NEG "becomes"
* (!!(r))
*/
r = n & 0x80000000;
printf("n & 0x80000000: 0x%x\n", r);
printf(" n = %s\n", bin(n, 32));
printf(" r = %s\n", bin(r, 32));
/* now we print what R is, so you see that the bitwise AND will
* return 0x80000000 on negative numbers. It will also print
* the NEGATION of R...
*
* After the printf(), we just assign the negated value to R.
*/
printf("r = 0x%x, !r = 0x%x\n", r, !r);
r = !r;
printf(" r = %s\n", bin(r, 32));
/* After this, IS_NEG "becomes" (!(r)) */
/* In the MACRO, this would be the second negation. */
printf("r = 0x%x, !r = 0x%x\n", r, !r);
r = !r;
printf(" r = %s\n", bin(r, 32));
/* Now, if R is 0, it means the number is either ZERO or
* POSITIVE.
*
* If R is 1, then the number is negative
*/
}
return 0;
}
https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign
Technically, an int could be a different size on different machines; use of an C99 int32_t from inttypes.h may help with portability. It might not even be encoded in the format you expect, Are there any non-twos-complement implementations of C?.
The really portable easy way, is of course,
static int is_positive(const int a) {
return a > 0;
}
The compiler will probably do a better job optimising it.
Edit: From comments, I came up with this; I tried to make it agnostic of the int-size. It is very much the same style as your own, checking whether the number is negative or zero, and inverting.
#include <stdio.h> /* printf */
#include <limits.h> /* INT_ */
#include <assert.h> /* assert */
/** Assumes a is a 2's-compliment number
and ~INT_MAX = 0b100..00, (checks if negative.) */
static int is_positive(const int a) {
unsigned b = a;
return !((b & ~INT_MAX) | !b);
}
static int is_really_positive(const int a) {
return a > 0;
}
static void test(const int a) {
printf("Number %d. Is positive %d.\n", a, is_positive(a));
assert(is_positive(a) == is_really_positive(a));
}
int main(void) {
test(INT_MIN);
test(-2);
test(-1);
test(0);
test(1);
test(2);
test(INT_MAX);
return 0;
}
Also related, https://stackoverflow.com/a/3532331/2472827.
Given the allowed operators from your comment, ! ~ & ^ | + << >>, edit: with the later constraint of no casts only the second alternative fits:
static int is_positive(unsigned x)
{
return ~x+1 >> (CHAR_BIT*sizeof x-1);
}
Here's the deal: conversion to unsigned is very carefully specified in C: if the signed value is unrepresentable in the unsigned type, one plus the maximum value representable in the unsigned type is added (or subtracted, no idea what prompted them to include this possibility) to the incoming value until the result is representable.
So the result depends only on the incoming value, not its representation. -1 is converted to UINT_MAX, no matter what. This is correct, since the universe itself runs on twos-complement notation . That it also makes the conversion a simple no-op reinterpretation on most CPUs is just a bonus.
You can get a 32-bit wide zero-or-nonzero test using bitwise or and shifts as follows:
int t;
t = x | (x>>16);
t = t | (t >> 8);
t = t | (t >> 4);
t = t | (t >> 2)
t = (t | (t>>1)) & 1;
This sets t to the "OR" of the low 32 bits of x and will 0 if and only if the low 32 bits are all zero. If the int type is 32 bits or less, this will be equivalent to (x != 0). You can combine that with your sign bit test:
return t & (~x >> 31);
To check whether given number is positive or negative. As you mentioned x is an int & I assume its 32-bit long signed int. for e.g
int x = 0x7fffffff;
How above x represented in binary
x => 0111 1111 | 1111 1111 | 1111 1111 | 1111 1111
| |
MSB LSB
Now to check given number is positive or negative using bitwise opaertor, just find out the status of last(MSB or 31st(longint) or 15th(short int)) bit status whether it's 0 or 1, if last bit is found as 0 means given number is positive otherwise negative.
Now How to check last bit(31st) status ? Shift last(31st) bit to 0th bit and perform bitwise AND & operation with 1.
x => 0111 1111 | 1111 1111 | 1111 1111 | 1111 1111
x>>31 => 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000
---------------------------------------------
&
1 => 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
---------------------------------------------
0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 => its binary of zero( 0 ) so its a positive number
Now how to program above
static inline int sign_bit_check(int x) {
return (x>>31) & 1;
}
And call the sign_bit_check() like
int main(void) {
int x = 0x7fffffff;
int ret = sign_bit_check(x);
if(ret) {
printf("Negative\n");
}
else {
printf("positive \n");
}
return 0;
}
I'm confused. Why in this program a gives me 0xFFFFFFA0 but b gives me 0xA0? It's weird.
#include <stdio.h>
int main()
{
char a = 0xA0;
int b = 0xA0;
printf("a = %x\n", a);
printf("b = %x\n", b);
}
Default type of a is signed in char a = 0xA0; and in any signed data type whether its char of int you should be careful of sign bit, if sign bit is set means number will be negative and store as two's compliment way.
char a = 0xA0; /* only 1 byte for a but since sign bit is set,
it gets copied into remaining bytes also */
a => 1010 0000
|
this sign bit gets copied
1111 1111 1111 1111 1111 1111 1010 0000
f f f f f f A 0
In case of int b = 0xA0; sign bit(31st bit) is 0 so what ever it contains i.e 0xA0 will be printed.
Let's take this step-by-step.
char a = 0xA0;
0xA0 in an integer constant with a value of 160 and type int.
In OP's case, a char is encoded like a signed char with an 8-bit range. 160 is more than the maximum 8-bit char and so assigning an out-of-range value to a some signed integer type is implementation defined behavior. In OP's case, the value "wrapped around" and a took on the value of 160 - 256 or -96.
// Try
printf("a = %d\n", a);
With printf() (a variadic function), char a it passed to the ... part and so goes though the usual integer promotions to an int and retains the same value.
printf("a = %x\n", a);
// is just like
printf("a = %x\n", -96);
printf("a = %x\n", a);
With printf(), "%x" expect an unsigned or an int with a value in the non-negative range. With int and -96, it is neither and so the output is undefined behavior.
A typical undefined behavior is this case is to interpret the passed bit pattern as an unsigned. The bit pattern of int -96, as a 32-bit int is 0xFFFFFFA0.
Moral of the story:
Enable a compile warnings. A good compiler would warn about both char a = 0xA0; and printf("a = %x\n", a);
Do not rely on undefined behavior.
I am trying to multiply two 8 bit numbers ans store the 16 bit result in two 8 bit variables, Eg :
91*16 = 1456
High = 14 and Low = 56
This is the code I'm using but not getting desired result . Can someone point out my error please?
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include<time.h>
int main()
{
uint8_t a = 91;
uint8_t b = 16;
uint16_t c = a*b;
printf("Value at c is %d \n",c);
uint8_t lo = c & 0x00FF;
uint8_t hi = c >> 8;
printf("Hi and lo value are %d and %d \n",hi,lo);
return 0;
}
I get Hi = 5 and Lo = 176, why is it so ?
Result of a*b is
0000 0101 1011 0000
( 5 )( 176 )
That is what you printed.
You mixed up decimal representation with others. The value you see is not stored like 0001 0100 0101 0110. If it was, then yes you would get your desired result (But it is debatable how helpful it would be).
To get what you want, you might consider using c%100 and c/100.(You are getting the most significant 2 digits in hi and rest two digits in lo).
uint8_t lo = c %100;
uint8_t hi = c /100;
And print them properly
printf("%" PRIu8 "\n", lo); //56
printf("%" PRIu8 "\n", hi); //14
In this way to be precise printf("Hi and lo value are %" PRIu8" and %"PRIu8" \n",hi,lo);.
Note that any 2 digit positive integer can be placed in uint8_t but to be more generic, you might want to consider that sometimes the resultant multiplication can be of 5 decimal digits.
If you want decimal representation (which doesn't make sense as decimal does not evenly divide byte values) you need to use /100 and %100 instead of bitwise operations.
I was thinking this world work, but it does not:
int a = -500;
a = a << 1;
a = (unsigned int)a >> 1;
//printf("%d",a) gives me "2147483148"
My thought was that the left-shift would remove the leftmost sign bit, so right-shifting it as an unsigned int would guarantee that it's a logical shift rather than arithmetic. Why is this incorrect?
Also:
int a = -500;
a = a << 1;
//printf("%d",a) gives me "-1000"
TL;DR: the easiest way is to use the abs function from <stdlib.h>. The rest of the answer involves the representation of negative numbers on a computer.
Negative integers are (almost always) represented in 2's complement form. (see note below)
The method of getting the negative of a number is:
Take the binary representation of the whole number (including leading zeroes for the data type, except the MSB which will serve as the sign bit).
Take the 1's complement of the above number.
Add 1 to the 1's complement.
Prefix a sign bit.
Using 500 as an example,
Take the binary representation of 500: _000 0001 1111 0100 (_ is a placeholder for the sign bit).
Take the 1's-complement / inverse of it: _111 1110 0000 1011
Add 1 to the 1's complement: _111 1110 0000 1011 + 1 = _111 1110 0000 1100. This is the same as 2147483148 that you obtained, when you replaced the sign-bit by zero.
Prefix 0 to show a positive number and 1 for a negative number: 1111 1110 0000 1100. (This will be different from 2147483148 above. The reason you got the above value is because you nuked the MSB).
Inverting the sign is a similar process. You get leading ones if you use 16-bit or 32-bit numbers leading to the large value that you see. The LSB should be the same in each case.
Note: there are machines with 1's complement representation, but they are a minority. The 2's complement is usually preferred because 0 has the same representation, i.e., -0 and 0 are represented as all-zeroes in the 2's complement notation.
Left-shifting negative integers invokes undefined behavior, so you can't do that. You could have used your code if you did a = (unsigned int)a << 1;. You'd get 500 = 0xFFFFFE0C, left-shifted 1 = 0xFFFFFC18.
a = (unsigned int)a >> 1; does indeed guarantee logical shift, so you get 0x7FFFFE0C. This is decimal 2147483148.
But this is needlessly complex. The best and most portable way to change the sign bit is simply a = -a. Any other code or method is questionable.
If you however insist on bit-twiddling, you could also do something like
(int32_t)a & ~(1u << 31)
This is portable to 32 bit systems, since (int32_t) guarantees two's complement, but 1u << 31 assumes 32 bit int type.
Demo:
#include <stdio.h>
#include <stdint.h>
int main (void)
{
int a = -500;
a = (unsigned int)a << 1;
a = (unsigned int)a >> 1;
printf("%.8X = %d\n", a, a);
_Static_assert(sizeof(int)>=4, "Int must be at least 32 bits.");
a = -500;
a = (int32_t)a & ~(1u << 31);
printf("%.8X = %d\n", a, a);
return 0;
}
As you put in the your "Also" section, after your first left shift of 1 bit, a DOES reflect -1000 as expected.
The issue is in your cast to unsigned int. As explained above, the negative number is represented as 2's complement, meaning the sign is determined by the left most bit (most significant bit). When cast to an unsigned int, that value no longer represents sign but increases the maximum value your int can take.
Assuming 32 bit ints, the MSB used to represent -2^31 (= -2147483648) and now represents positive 2147483648 in an unsigned int, for an increase of 2* 2147483648 = 4294967296. Add this to your original value of -1000 and you get 4294966296. Right shift divides this by 2 and you arrive at 2147483148.
Hoping this may be helpful: (modified printing func from Print an int in binary representation using C)
void int2bin(int a, char *buffer, int buf_size) {
buffer += (buf_size - 1);
for (int i = buf_size-1; i >= 0; i--) {
*buffer-- = (a & 1) + '0';
a >>= 1;
}
}
int main() {
int test = -500;
int bufSize = sizeof(int)*8 + 1;
char buf[bufSize];
buf[bufSize-1] = '\0';
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -500 (4294966796): 11111111111111111111111000001100
test = test << 1;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -1000 (4294966296): 11111111111111111111110000011000
test = 500;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: 500 (500): 00000000000000000000000111110100
return 0;
}