Hex char to int conversion - c

I'm reading data from UART byte by byte. This is saved to a char.
The byte following the start byte gives the number of subsequents bytes incoming (as a hexadecimal). I need to convert this hex number to an integer, to keep count of bytes required to be read.
Presently I'm simply type-casting to int. Here's my code:
char ch;
int bytes_to_read;
while(1){
serial_read(UART_RX, &ch, sizeof(char));
if(/*2nd byte*/){
bytes_to_read = (int)ch;
}
}
I read about strtol(), but it takes char arrays as input. What's the right way to do this?

Your question is unclear, but assuming that ch is a hexadecimal character representing the number of bytes, then you could just use a simple function to convert from hex to int, e.g.
int hex2int(char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0';
if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
return -1;
}
and then:
bytes_to_read = hex2int(ch);
Note however that if ch is really just a raw value (i.e. not a hex character) then your existing method should be fine:
bytes_to_read = (int)ch;

strtol works on a string, ch is a char, so convert this char to a valid string
char str[2] = {0};
char chr = 'a';
str[0] = chr;
and use strtol with base 16:
long num = strtol(str, NULL, 16);
printf("%ld\n", num);

i think easy way :
unsigned char x = 0xff;
int y = (int) x;
printf("Hex: %X, Decimal: %d\n",x,x);
printf("y = %d",y);
for more info :
https://www.includehelp.com/c/working-with-hexadecimal-values-in-c-programming-language.aspx

Related

How do I get my integer arithmetic into a long long?

As part of exercise 2-3 in Ritchie and Kernighan's C programming language, I've written a program that converts hexadecimal inputs into decimal outputs. I want it to be able to handle larger numbers, but it seems to be doing integer arithmetic somewhere. When you enter something like "DECAFCAB" it spits out a large negative int. I figured out that I need to add the "LL" suffix to my literals, which I did, but it's still not working. Any help please? Sorry if this is a dumb question or a typo, but I've been at it for an hour and can't figure it out. :(
#include <stdio.h>
#define MAX_LINE 1000
void getline(char s[])
{
int i;
char c;
for(i = 0; i < MAX_LINE-1 && (c=getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
s[i] = '\0';
printf("\n%s", s);
}
long long htoi(char s[]) // convert the hex string to dec
{
long long n = 0;
int i = 0;
if(s[i] == '0') // eat optional leading Ox or OX
++i;
if(s[i] == 'x' || s[i] == 'X')
++i;
while(s[i] != '\0')
{
if((s[i] >= '0' && s[i] <= '9'))
n = 16LL * n + (s[i] - '0'); // here is the arithmetic in question
else if(s[i] >= 'A' && s[i]<= 'F')
n = 16LL * n + (s[i] - 'A' + 10LL);
else if(s[i] >= 'a' && s[i] <= 'f')
n = 16LL * n + (s[i] - 'a' + 10LL);
else {
printf("\nError: Encountered a non-hexadecimal format: the '%c' character was unexpected.", s[i]);
printf("\nHexadecimal numbers can begin with an optional 0x or 0X only, and contain 0-9, A-F, and a-f.\n\n");
return -1;
}
++i;
}
return n;
}
main()
{
char input[MAX_LINE];
long long hex_output;
while(1){
getline(input);
hex_output = htoi(input);
if(hex_output >= 0)
printf("\nThe value of the hexadecimal %s is %d in decimal.\n\n", input, hex_output);
}
}
You told printf to expect an int when you made the placeholder %d. To make it expect (and therefore read the entirety of a) long long, modify it to %lld.
The reason it looks like a plain int is that with varargs functions like printf, it doesn't know what the argument sizes are, and the format string is the only way to figure it out. When you say to expect plain int, it reads sizeof(int) bytes from the argument, not sizeof(long long) bytes (it's not necessarily byte-oriented, but that's how much data is read), and (on a little endian system with 4 byte int and 8 byte long long) you see (roughly) the result of the argument with the top 4 bytes masked off.
The problem you are experiencing comes from treating a (conventionally) "unsigned" hexadecimal integer value as "signed". Resorting using to a larger built-in data type will get you past the problem with going from 31 to 32 bits, but this masks the actual problem. (If you extend to 64 bits, you will encounter the same problem and be back asking, "why doesn't this work.")
Better is to write code that doesn't require ever wider registers. There will always be a maximum width, but the answer to this OP is to use an "unsigned long".
#include <stdio.h>
unsigned long htoi( char s[] ) { // convert the hex string to dec
unsigned long n = 0;
int i = 0;
if(s[i] == '0') // eat optional leading Ox or OX
++i;
if(s[i] == 'x' || s[i] == 'X')
++i;
for( ; s[i]; i++ ) {
unsigned int dVal = 0; // don't copy/paste complex statements.
if((s[i] >= '0' && s[i] <= '9'))
dVal = s[i] - '0'; // simple
else if(s[i] >= 'A' && s[i]<= 'F')
dVal = s[i] - 'A' + 10; // simple
else if(s[i] >= 'a' && s[i] <= 'f')
dVal = s[i] - 'a' + 10; // simple
else {
// less verbose
printf("\nError: '%c' unexpected.", s[i] );
return 0; // NB: Notice change!!
}
n = (16 * n) + dVal; // simple...
}
return n;
}
int main() {
// simplified, stripping out user input.
char *hexStr = "0xDECAFCAB";
unsigned long hex_output = htoi( hexStr );
// Notice the format specifier to print an ordinary (unsigned) long
printf( "\nThe value of the hexadecimal %s is %u in decimal.\n\n", hexStr, hex_output );
return 0;
}
The value of the hexadecimal 0xDECAFCAB is 3737844907 in decimal.
When K&R wrote the original book, there was no such thing as "long long", but there was "unsigned long".

Converting from hexadecimal to decimal number in C

I am doing the exercise in the C Programming language book, and exercise 2-3 asked us to write a function htoi to convert a hexadecimal number to decimal number.
This is the code I wrote, however when it runs, it always show that my hexadecimal number is illegal.
Please help!
#include<stdio.h>
#define TRUE 1
#define FALSE 0
int htoi (char s[]);
int main() {
printf("The decimal number is %d\n", htoi("0x134"));
return 0;
}
int htoi (char s[]) {
int j; /* counter for the string */
int temp; /* temp number in between conversion */
int number; /* the converted number */
int ishex; /* if the number is a valid hexadecimal number */
char c;
number = 0;
temp = 0;
ishex = FALSE;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
ishex = TRUE;
}
else {
ishex = FALSE;
printf("This is not valid hexadecimal number.\n");
return number = 0;
}
if (ishex == TRUE) {
for (j = 2; (c = s[j]) != EOF; ++j) {
if (c >= '0' && c <= '9')
temp = c - '0';
else if (c >= 'a' && c <= 'f')
temp = 10 + c - 'a';
else if (c >= 'A' && c <= 'F')
temp = 10 + c - 'A';
else {
printf("This is a illegal hexadecimal number.\n");
ishex = FALSE;
return 0;
}
number = number * 16 + temp;
}
}
return number;
}
A string is a sequence of characters that terminates at the first '\0' character. That means "0x134" terminates with a '\0' character value, not an EOF value.
You are operating on a sequence of characters that you expect to be terminated by an EOF value, but that is simply not possible. I'll explain why later... Suffice to say for now, the string "0x134" contains no EOF value.
Your loop reaches the string-terminating '\0', which isn't in the range 0..9, a..f or A..F and so this branch executes:
else {
printf("This is a illegal hexadecimal number.\n");
ishex = FALSE;
return 0;
}
Perhaps you meant to write your loop like so:
for (j = 2; (c = s[j]) != '\0'; ++j) {
/* SNIP */
}
I promised to explain what is wrong with expecting EOF to exist as a character value. Assuming an unsigned char is 8 bits, getchar can return one of 256 character values, and it will return them as a positive unsigned char value... OR it can return the negative int value EOF, corresponding to an error or end-of-file.
Confused? In an empty file, there are no characters... Yet if you try to read a character from the file, you will get EOF every time, in spite of there being no characters. Hence, EOF is not a character value. It's an int value, and should be treated as such before you attempt to convert the value to a character, like so:
int c = getchar();
if (c == EOF) {
/* Here, c is NOT A CHARACTER VALUE! *
* It's more like an error code ... *
* XXX: Break or return or something */
}
else {
/* Here, c IS a character value, ... *
* so the following conversion is ok */
char ch = c;
}
On another note, c >= '0' && c <= '9' will evaluate truthfully when c is one of the digits in the range 0..9... This is a requirement from the C standard
Neither c >= 'a' && c <= 'f' nor c >= 'A' && c <= 'F' are required to evaluate truthfully under any circumstance, however. It happens to work on your system, because you are using ASCII which contains all of the lowercase letters in one contiguous block, and all of the uppercase letters in another contiguous block. C does not require that ASCII be the character set.
If you want this code to work portably, you might consider something like:
char alpha_digit[] = "aAbBcCdDeEfF";
if (c >= '0' && c <= '9') {
c -= '0';
}
else if (strchr(alpha_digit, c)) {
c = 10 + (strchr(alpha_digit, c) - alpha_digit) / 2;
}
else {
/* SNIP... XXX invalid digit */
}

Bizzare behavior from C program:: Kernighan & Ritchie exercise 2-3

all.
I've written a program as a solution to Kernighan & Ritchie's exercise 2-3, and its behaviour during testing is (IMHO) wildly unintuitive.
The problem spec says to write a program that converts hex values to their decimal equivalent. The code I've written works fine for smaller hex values, but for larger hex values things get a little... odd. For example, if I input 0x1234 the decimal value 4660 pops out on the other end, which happens to be the correct output (the code also works for letters, i.e. 0x1FC -> 508). If, on the other hand, I were to input a large hex value, say as a specific example 0x123456789ABCDEF, I should get 81985529216486895, though instead I get 81985529216486896 (off by one digit!).
The error in conversion is inconsistent, sometimes with the decimal value being too high and other times too low. Generally, much larger hex values result in more incorrect place values in the decimal output.
Here's my program in its entirety:
/*Kernighan & Ritchie's Exercise 2-3
Write a function 'htoi' which converts a string of hexadecimal digits (including an
optional 0x or 0X) into its equivalent integer value.
*/
#include <stdio.h>
#define MAXLINE 1000 //defines maximum size of a hex input
//FUNCTION DEFINITIONS
signed int htoi(char c); //converts a single hex digit to its decimal value
//BEGIN PROGRAM////////////////////////////////////////////////////////////
main()
{
int i = 0; //counts the length of 'hex' at input
char c; //character buffer
char hex[MAXLINE]; //string from input
int len = 0; //the final value of 'i'
signed int val; //the decimal value of a character stored in 'hex'
double n = 0; //the decimal value of 'hex'
while((c = getchar()) != '\n') //store a string of characters in 'hex'
{
hex[i] = c;
++i;
}
len = i;
hex[i] = '\0'; //turn 'hex' into a string
if((hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) //ignore leading '0x'
{
for(i = 2; i < len; ++i)
{
val = htoi(hex[i]); //call 'htoi'
if(val == -1 ) //test for a non-hex character
{
break;
}
n = 16.0 * n + (double)val; //calculate decimal value of hex from hex[0]->hex[i]
}
}
else
{
for(i = 0; i < len; ++i)
{
val = htoi(hex[i]); //call 'htoi'
if(val == -1) //test for non-hex character
{
break;
}
n = 16.0 * n + (double)val; //calc decimal value of hex for hex[0]->hex[i]
}
}
if(val == -1)
{
printf("\n!!THE STRING FROM INPUT WAS NOT A HEX VALUE!!\n");
}
else
{
printf("\n%s converts to %.0f\n", hex, n);
}
return 0;
}
//FUNCTION DEFINITIONS OUTSIDE OF MAIN()///////////////////////////////////
signed int htoi(char c)
{
signed int val = -1;
if(c >= '0' && c <= '9')
val = c - '0';
else if(c == 'a' || c == 'A')
val = 10;
else if(c == 'b' || c == 'B')
val = 11;
else if(c == 'c' || c == 'C')
val = 12;
else if(c == 'd' || c == 'D')
val = 13;
else if(c == 'e' || c == 'E')
val = 14;
else if(c == 'f' || c == 'F')
val = 15;
else
{
;//'c' was a non-hex character, do nothing and return -1
}
return val;
}
pastebin: http://pastebin.com/LJFfwSN5
Any ideas on what is going on here?
You are probably exceeding the precision with which double can store integers.
My suggestion would be to change your code to use unsigned long long for the result; and also add in a check for overflow here, e.g.:
unsigned long long n = 0;
// ...
if ( n * 16 + val < n )
{
fprintf(stderr, "Number too big.\n");
exit(EXIT_FAILURE);
}
n = n * 16 + val;
My less-than check works because when unsigned integer types overflow they wrap around to zero.
If you want to add more precision than unsigned long long then you will have to get into more advanced techniques (probably beyond the scope of Ch. 2 of K&R but once you've finished the book you could revisit).
NB. You also need to #include <stdlib.h> if you take my suggestion of exit; and don't forget to change %.0f to %llu in your final printf. Also, a safer way to get the input (which K&R covers) is:
int c;
while((c = getchar()) != '\n' && c != EOF)
The first time I ran the code on ideone I got segfault, because I didn't put a newline on the end of the stdin so this loop kept on shoving EOF into hex until it buffer overflowed.
This is a classic example of floating point inaccuracy.
Unlike most of the examples of floating point errors you'll see, this is clearly not about non-binary fractions or very small numbers; in this case, the floating point representation is approximating very big numbers, with the accuracy decreasing the higher you go. The principle is the same as writing "1.6e10" to mean "approximately 16000000000" (I think I counted the zeros right there!), when the actual number might be 16000000001.
You actually run out of accuracy sooner than with an integer of the same size because only part of the width of a floating point variable can be used to represent a whole number.

C printf unsigned char array

I have an unsigned char array unsigned char* name = malloc(nameLength); - how can I print it with printf? %sdoes not seem to work correctly, neither does %u (seeing random icons).
Here's how I create the data I want to print:
__int32 nameLength;
ReadProcessMemory(hProcess, (LPCVOID)(classNamePtr + 0x0004), &nameLength, sizeof(__int32), 0); //Reads nameLength to be 13 in this case
unsigned char* name = malloc(nameLength+5); //Add 5 for good measure, it is null terminated
ReadProcessMemory(hProcess, (LPCVOID)(nameStrPtr), name, nameLength, 0);
name[nameLength] = 0; //null terminate
printf("%s", name); //Outputs single character strange characters, like an up icon
When one detects a non-printable char, output an escape sequence or hexadecimal value
#include <ctype.h>
#include <string.h>
#include <stdio.h>
int printf_ByteArray(const unsigned char *data, size_t len) {
size_t i;
int result = 0;
for (i = 0; i < len; i++) {
int y;
int ch = data[i];
static const char escapec[] = "\a\b\t\n\v\f\n\'\"\?\\";
char *p = strchr(escapec, ch);
if (p && ch) {
static const char escapev[] = "abtnvfn\'\"\?\\";
y = printf("\\%c", escapev[p - escapec]);
} else if (isprint(ch)) {
y = printf("%c", ch);
} else {
// If at end of array, assume _next_ potential character is a '0'.
int nch = i >= (len - 1) ? '0' : data[i + 1];
if (ch < 8 && (nch < '0' || nch > '7')) {
y = printf("\\%o", ch);
} else if (!isxdigit(nch)) {
y = printf("\\x%X", ch);
} else {
y = printf("\\o%03o", ch);
}
}
if (y == EOF)
return EOF;
result += y;
}
return result;
}
If data contained one of each byte, sample follows:
\0...\6\a\b\t\n\v\f\xD\xE\xF\x10...\x1F !\"#$%&\'()*+,-./0123456789:;<=>\?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F...\xFE\o377
The selection of escape sequences will vary with code goals. The set above attempts to conform to something a C parser would accept.
Note: With the last else, always outputting a 3-digit octal sequence has scanning advantages, but folks are more accustomed to hexadecimal than octal.
Adjusted to conditionally print in hex depending on the following character.

Convert to negative integer by reading characters

This is a program which reads data character by character until it finds a character digit and converts it into an integer.
#include <stdio.h>
int main(void) {
char ch = getchar();
printf("Type some data including a number");
while(ch < '0' || ch > '9') //as long as the character is not a digit.
{
ch = getchar();
}
int num = 0;
while(ch >= '0' && ch <= '9') //as long as we get a digit
{
num = num * 10 + ch - '0'; //convert char digit to integer
ch = getchar();
}
printf("Number is %d\n",num);
}
This program only finds positive integers. I want the program to find negative integers aswell or floating point number. How do i make the program to do that? I tried using if statement inside the while loop that looks for a digit but that didnt work for me.
It appears as though fscanf will be a better solution
E.g
#include <stdio.h>
#include <ctype.h>
int main(void) {
//input format ([^0-9]*-)?[0-9]+
int ch, sign = 1;
while(!isdigit(ch=getchar())){
if(ch=='-'){
ch=getchar();//one character look-ahead
if(isdigit(ch)){
sign = -1;
}
ungetc(ch, stdin);//push back
}
}
int num;
for(num=0;isdigit(ch);ch = getchar()){
num = num * 10 + ch - '0';
}
num *= sign;
printf("Number is %d\n",num);
return 0;
}

Resources