I have a function that is aimed at getting the value of two chars added together into a short. It seems that the value is getting cut off or mangled.
Here is my code:
char rotate(char a, char b){
unsigned short x = a + b;
printf("init:%hu %hu = %hu\n", (unsigned char)a, (unsigned char)b, (unsigned short)x);
if(x > 255){
x -= 255;
}
return (char) x;
}
unsigned char x = rotate((unsigned char)230, (unsigned char)100);
unsigned char y = rotate((unsigned char )200, (unsigned char)200);
unsigned char z = rotate((unsigned char) 230, (unsigned char)120);
and the results are
init:230 100 = 74
init:200 200 = 65424
init:230 120 = 94
Addition is done with original values and is correct.
unsigned short x = a + b;
Yet display is done with converted values.
printf("init:%hu %hu = %hu\n", (unsigned char)a, (unsigned char)b, ....
Print the char original values.
#if CHAR_MAX <= INT_MAX
printf("a:%d b:%d\n", a, b);
#else
// this is rare
printf("a:%u b:%u\n", a, b);
#endif
OP will see the first addition is init:-26 100 = 74 and the sum of 74 is as expected.
With init:200 200 = 65424, the original char values are -56. -56 + -56 is -112. Assigning -112 to a 16-bit unsigned short (0-65535) adds 65536 and then assigns. -112 + 65536 --> 65424.
Related
I have been assigned with a task to perform unsigned multiplication using signed multiplier. Despite multiple attempts, I couldn't get it. Is it possible to do this?
Code:
#include <stdio.h>
int main()
{
// Must be short int
short int a=0x7fff;
short int b=0xc000;
unsigned int res1;
signed int res2;
//unsigned multiplier
res1= (unsigned short int) a * (unsigned short int) b;
//signed multiplier
res2= (short int) a * (short int) b;
printf("res1: 0x%x %d \n res2: 0x%x %d\n",res1,res1,res2,res2);
return 0;
}
This is the code provided.
Current Output:
res1: 0x5fff4000 1610563584
res2: 0xe0004000 -536854528
Expected Output:
res1: 0x5fff4000 1610563584
res2: 0x5fff4000 1610563584
Working Code:
#include<stdio.h>
#include<conio.h>
int main()
{
short int a = 0x7fff;
short int b = 0x3000;
unsigned int unsignedRes;
signed int signedRes;
unsigned int ourRes;
// Unsigned Multiplier
unsignedRes = (unsigned short int) a * (unsigned short int) b;
// Signed Multiplier
signedRes = (short int) a * (short int) b;
// Our Code using SIgned Multiplier
ourRes = ((short int)a & ~(0xffffu << 16))*((short int)b & ~(0xffffu << 16));
printf("Expected: 0x%x\nSigned: 0x%x\nResult: 0x%x",unsignedRes,signedRes,ourRes);
getch();
return 0;
}
The assignment short int b=0xc000; alone is already implementation defined (vid.: ISO/IEC 9899:2018 6.3.1.3 p. 3) and would need to be done in two parts b = b1 * 2^15 + b0 = 0x1*2^15 + 0x4000 (assuming SHRT_MAX + 1 == 32768 ). If you do both in two parts like that and understand the assignment in such a way that the result is an unsigned data type and do a*b == (a1 * 2^15 + a0) * (b1 * 2^15 + b0) by using unsigned int ret2 for the result and signed int temporary variables for the rest.
Assuming that the input is restricted to the capabilities of an unsigned short int (unsigned because of 0xc000) and that all types must be signed types with the exception of the output:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(void)
{
/*
This whole thing has ben pulled apart for clarity and could (should!) be done
in less lines of code.
All implicit type conversions are made explicit.
We also assume 2s complement (and a little bit more, to be honest).
*/
/*
A and B limited to 0xffff to keep this code simple.
If you want to get rid of these limits you need to count the bits
of A and B and make sure that the sum does not exceed sizeof(int)*CHAR_BIT-1
*/
signed int A = 0x7fff;
signed int B = 0xc000;
short int a0, a1;
short int b0, b1;
signed int shift = SHRT_MAX+1;
unsigned int res1, res2;
/* Additional temporary variables for legibility */
signed int t0, t1, t2, t3;
/* Check input range */
if ((A > 0xffff) || (B > 0xffff)) {
fprintf(stderr,"Input must not exceed 0xffff! A = 0x%x, B = 0x%x\n",A,B);
exit(EXIT_FAILURE);
}
//unsigned multiplier
res1 = (unsigned int)A * (unsigned int)B;
//signed multiplier
/* Compute A*B == (a1 * shift + a0) * (b1 * shift + b0) */
a0 = (short int)(A % shift);
a1 = (short int)(A / shift);
b0 = (short int)(B % shift);
b1 = (short int)(B / shift);
/*
Multiply out for convenience:
A*B == (a1 * 2^15 + a0) * (b1 * 2^15 + b0)
== a1 * b1 *2^15 * 2^15
+ a0 * b1 * 2^15
+ a1 * b0 * 2^15
+ a0 * b0
*/
/*
Here a1 and b1 are either 0 (zero) or 1 (one) and (SHRT_MAX+1)^2 < INT_MAX
so t0 cannot overflow.
You should make use of that fact in production.
*/
t0 = (signed int)a1 * (signed int)b1 * shift * shift; /* t0 in {0,shift^2} */
t1 = (signed int)a0 * (signed int)b1 * shift; /* t1 in {0, a0 * shift} */
t2 = (signed int)a1 * (signed int)b0 * shift; /* t2 in {0, b0 * shift} */
t3 = (signed int)a0 * (signed int)b0; /* t3 can get larger than INT_MAX! */
/* Cannot overflow because floor(sqrt(2^32-1)) = 0xffff and both A and B < 0xfff */
res2 = (unsigned int)t0 + (unsigned int)t1 + (unsigned int)t2 + (unsigned int)t3;
printf("res1: 0x%x %d\nres2: 0x%x %d\n",res1, res1, res2, res2);
exit(EXIT_SUCCESS);
}
The assignment is rather under-defined, to keep it polite, but as I do not know if it is your fault, the teacher's fault or a bad zoom-connection I tried to give you a couple of directions. If it wasn't wat was expected you should at least be able to ask the right questions now.
I was given a task at the university, there is a number and I need to display it in HEX as it is presented on the computer. I wrote a program for translating signed integers. And I also found a real number entry in HEX. But it is different from the usual.
For integers i use: printf("%#X", d);
For reals i use: printf("%#lX", r);
If i input 12, first prints: 0xC
If i input 12.0, second prints: 0x4028000000000000
Can you explain what the difference and how it's calculate?
Printing double value r using format %#lX actually has undefined behavior.
You have been lucky to get the 64-bits that represent the value 12.0 as a double, unless r has type unsigned long and was initialized from the value 12.0 this way:
unsigned long r;
double d = 12.0;
memcpy(&r, &d, sizeof r);
printf("%#lX", r);
But type unsigned long does not have 64-bits on all platforms, indeed it does not on the 32-bit intel ABI. You should use the type uint64_t from <stdint.h> and the conversion format from <inttypes.h>:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
int main() {
int x = 12;
printf("int: %#X [", x);
for (size_t i = 0; i < sizeof x; i++) {
printf(" %02X", ((unsigned char *)&x)[i]);
}
printf(" ]\n");
double d = 12.0;
uint64_t r;
memcpy(&r, &d, sizeof r);
printf("double: %#"PRIX64" [", r);
for (size_t i = 0; i < sizeof d; i++) {
printf(" %02X", ((unsigned char *)&d)[i]);
}
printf(" ]\n");
printf("sign bit: %d\n", (int)(r >> 63));
printf("exponent: %d\n", (int)((r >> 52) & 2047));
unsigned long long mantissa = r & ((1ULL << 52) - 1);
printf("mantissa: %#llX, %.17f\n",
mantissa, 1 + (double)mantissa / (1ULL << 52));
return 0;
}
Output:
int: 0XC [ 0C 00 00 00 ]
double: 0X4028000000000000 [ 00 00 00 00 00 00 28 40 ]
sign bit: 0
exponent: 1026
mantissa: 0X8000000000000, 1.50000000000000000
As explained in the article Double-precision floating-point format, this representation corresponds to a positive number with value 1.5*21026-1023, ie: 1.5*8 = 12.0.
The X format specifier expects an int or unsigned int argument. With the l modifier it expects a long or unsigned long int argument. If you call it with anything else (such as a double) you get undefined behavior.
If you want to print a hex float (with uppercase letters), use %A format, which for 12.0 will print 0X1.8P+3 -- 1½×23
To produce the encoding of a number in hex is a simple memory dump.
The process is not so different among types.
The below passes the address of the object and its size to form a string for printing.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
// .... compound literal ....................
#define VAR_TO_STR_HEX(x) obj_to_hex((char [(sizeof(x)*CHAR_BIT + 3)/4 + 1]){""}, &(x), sizeof (x))
char *obj_to_hex(char *dest, void *object, size_t osize) {
const unsigned char *p = (const unsigned char *) object;
p += osize;
char *s = dest;
while (osize-- > 0) {
p--;
unsigned i = (CHAR_BIT + 3)/4;
while (i-- > 0) {
unsigned digit = (*p >> (i*4)) & 15;
*s++ = "0123456789ABCDEF"[digit];
}
}
*s = '\0';
return dest;
}
int main(void) {
double d = 12.0;
int i = 12;
printf("double %s\tint %s\n", VAR_TO_STR_HEX(d), VAR_TO_STR_HEX(i) );
d = -d;
i = -i;
printf("double %s\tint %s\n", VAR_TO_STR_HEX(d), VAR_TO_STR_HEX(i) );
return 0;
}
Output
double 4028000000000000 int 0000000C
double C028000000000000 int FFFFFFF4
With more complex objects, the output may include padding bits/bytes and the output is sensitive to endian.
I have an issue i can't solve. The code below should get a number from the user and a number of rotations. The code should calculate the number after the rotations. For negative number of rotations the code should rotate the number left and for positive number of rotation the code should rotate the number right.
For example: for the input x=1010111011111011
my_rotate(x, -3) will return 0111010111011111
my_rotate(x, 3) will return 0111011111011101
Here is the code i wrote so far:
#include <stdio.h>
unsigned short my_rotate(unsigned short, char);
int main()
{
unsigned short num, res;
char rotations;
printf("\nPlease enter a number and number of rotations\n");
scanf("%hu %d", &num, &rotations);
res = my_rotate(num, rotations);
return 0;
}
unsigned short my_rotate(unsigned short a, char b)
{
unsigned short bitsNum = sizeof(unsigned short) * 8;
unsigned short temp1, temp2, result;
if(b == 0)
return a;
else if(b < 0)
{
temp1 = a << (bitsNum + b);
temp2 = a >> (-b);
result = temp1 + temp2;
}
else /* b > 0 */
{
temp1 = (a >> (bitsNum - (unsigned short)b));
temp2 = (a << (unsigned short)b);
result = temp1 + temp2;
}
return result;
}
I always get 0 as a result and i don't know why. What's wrong with my code?
in main :
unsigned short num, res;
char rotations;
printf("\nPlease enter a number and number of rotations\n");
scanf("%hu %d", &num, &rotations);
the last argument of scanf must be a pointer to an int (format is %d) but you give the address of a char, the behavior is undefined. Use an int for rotations for the format %d
In my_rotate b is a char and you do if(b < 0), the result depends if the char are signed or not, type n with signed char if you expect a char to be signed
If rotations is an int and b a signed char :
44795 (1010111011111011) and -3 produce 30175 being 111010111011111
44795 (1010111011111011) and 3 produce 30685 being 111011111011101
as you expected.
Note for me an unsigned short is on 16 bits, of course the result is not the same if short are on a different number of bit.
#bruno well explained a problem with input.
A rotation count may exceed +/- bitsNum, so a good first step is to limit the rotation count.
unsigned short my_rotate(unsigned short a, int b) {
unsigned short bitsNum = sizeof(unsigned short) * 8;
//add
b %= bitsNum;
....
Highly portable code would not use bitsNum as that is derived by the size of unsigned short (and assumes 8 bits/char) and an unsigned short could have padding bits. Certainly this is more of a rare machine concern. Code should derive the bit width based on USHRT_MAX instead.
I would like to use an unsigned char as a byte. I would expect that it would have a range from 0 to 255.
I defined the following macro:
#define ROTATE_LEFT(BYTE) ((BYTE & 128) > 0) ? ((BYTE << 1) | 1) : (BYTE << 1)
I would like to rotate it to the left.
Now I tested it by:
unsigned char c1 = 1;
unsigned char c2 = 128;
unsigned char c3 = 255;
unsigned char c4 = 200;
printf("%u\n", ROTATE_LEFT(c1)); // Expected: 2, Result: 2
printf("%u\n", ROTATE_LEFT(c2)); // Expected: 1, Result: 257
printf("%u\n", ROTATE_LEFT(c3)); // Expected: 255, Result: 511
printf("%u\n", ROTATE_LEFT(c4)); // Expected: 145, Result: 401
As you can see, I get results that should't be even possible.
What is wrong?
This because of integer promotion.
Your results are bring promoted to larger integers before being passed to printf.
You could store the result back into your variable, before passing that variable to printf. They will necessarily be truncated.
Also, the printf specifier for an unsigned char is %hhu.
Finally, I would suggest the following (untested) instead:
static inline uint8_t rol8(uint8_t x)
{
uint8_t low = (x & (1<<7)) >> 7;
return (x << 1) | low;
}
Just like this:
unsigned char c4 = 200;
printf("%u\n", c4 + 56);
output: 256
It's nothing to do with the unsigned char type of c4, you just pass a greater-than-255 value to printf function.
I want to read in an int. For example 001. After I want to cut up the into so that A = 0, B = 0 and C = 1. I want to do this in C. Thanks!
If 001 is a bit representation of your integer value I, then:
int A = (I >> 2) & 0x1
int B = (I >> 1) & 0x1
int C = I & 0x1
You can achieve the result wanted by using modulus operator (%) and integer division (/). It's easier to understand than bitwise operators when you're starting to learn C.
scanf("%d", &i);
a = i / 100;
b = (i % 100) / 10;
c = (i % 100) % 10;
Building on Karl Bielefeldt's comment:
You can create a union of a char and a bitfield such as:
typedef union
{
unsigned char byte;
unsigned char b0 : 1;
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
}TYPE_BYTE;
TYPE_BYTE sample_byte;
...then assign a value to sample_byte.byte and access each individual bit as sample_byte.b0, sample_byte.b1, etc. The order in which the bits are assigned is implementation dependent--read your compiler manual to see how it implements bitfields.
Bitfields can also be created with larger int types.
Edit (2011-03-15):
Assuming that maybe you want to read in a 3-digit base-10 integer and split the three digits into three variables, here's some code that should do that. It hasn't been tested so you might need to do some tweaking:
void split_base10(const unsigned int input, unsigned int *a, unsigned int *b, unsigned int *c)
{
unsigned int x = input;
*c = x%10;
x /= 10;
*b = x%10;
*a = x/10;
}
Good luck!