C read X bytes from a file, padding if needed - c

I am trying to read in an input file 64 bits at a time, then do some calculations on those 64 bits, the problem is I need to convert the ascii text to hexadecimal characters. I have searched around but none of the answers posted seem to work for my situation.
Here is what I have:
int main(int argc, int * argv)
{
char buffer[9];
FILE *f;
unsigned long long test;
if(f = fopen("input2.txt", "r"))
{
while( fread(buffer, 8, 1, f) != 0) //while not EOF read 8 bytes at a time
{
buffer[8] = '\0';
test = strtoull(buffer, NULL, 16); //interpret as hex
printf("%llu\n", test);
printf("%s\n", buffer);
}
fclose(f);
}
}
For an input like this:
"testing string to hex conversion"
I get results like this:
0
testing
0
string t
0
o hex co
0 nversion
Where I would expect:
74 65 73 74 69 6e 67 20 <- "testing" in hex
testing
73 74 72 69 6e 67 20 74 <- "string t" in hex
string t
6f 20 68 65 78 20 63 6f <- "o hex co" in hex
o hex co
6e 76 65 72 73 69 6f 6e <- "nversion" in hex
nversion
Can anyone see where I misstepped?

strtoull converts a number represented by a string into an unsigned long long. Your input to this function (eg. string "testing") makes no sense as it has to be a number.
printf("%llu\n", strtoull("123")); // prints 123
To get the result you want, you have to print each character of the string like this:
for(int i=0; i<8; i++)
printf( "%02X ", (unsigned char) buffer[i]);

The function strtoull (with 16) converts HEX string to number, not ASCII char to HEX string.
To print a char in HEX form, you should do something like printf("%02x ",buffer[0]);

strtoull() Converts a string that is in hex format (e.g. 0xFFAABBEE) to it's integer format.
What you really need is a function to convert a string to a hex string, like this:
char *strToHex(const char *input)
{
char *output = calloc(1, strlen(input) * 3 + 1);
char *o = output;
int i = 0;
for (; input[i] != '\0'; o += 3, i++)
{
sprintf(o, "%.2X ", input[i]);
}
// don't forget to free output!
return output;
}

Consider using limits.h as well.
I went a bit overboard but perhaps some of this fits:
Edit: [
Ehrmf. Perhaps a define of BITS_ULL is more fitting to your quest.
I.e. something in the direction of:
#define BITS_ULL (sizeof(unsigned long long) * CHAR_BIT)
#define BYTE_ULL (sizeof(unsigned long long))
And then read BYTE_ULL bytes, but make shure to check size of read bytes and not if it is -1 as latter could be a smash. I'm a bit unsure what you mean by "calculations" on read bits.
You could read BYTE_ULL bytes and cast to unsigned long long by address of buffer[0], or bit shift taking byte order into consideration. Or former and sort bytes with char pointer.
Also note that I have used len instead of null terminated / C string.
Oh, this is lots of fun :) - I'm learning, and this kind of hacking is heaven.
]
#include <stdio.h>
#include <limits.h> /* BITS */
#include <ctype.h> /* isprint() */
#define CHUNK_BITS 62
#define CHUNK_CHAR (CHUNK_BITS / CHAR_BIT)
#define HEX_WIDTH 2
/* print len hex values of s, separate every sep byte with space,
* but do not add trailing space. */
void prnt_cshex(const char *s, int len, int sep)
{
const unsigned char *p = (const unsigned char*)s;
int i;
for (i = 1; i <= len; ++p, ++i)
fprintf(stdout,
"%02x"
"%s",
*p,
(i < len && !((i)%sep) ? " " : ""));
}
/* Print len bytes of s, print dot if !isprint() */
void prnt_csbytes(const char *s, int len)
{
int i = 0;
for (i = 0; i < len; ++s, ++i)
fprintf(stdout,
"%c",
(isprint(*s) ? *s : '.'));
}
/* Pass file as first argument, if none, use default "input.txt" */
int main(int argc, char *argv[])
{
const char *fn = "input.txt";
FILE *fh;
char buffer[CHUNK_CHAR];
const char *p = &buffer[0];
size_t k;
if (argc > 1)
fn = argv[1];
if ((fh = fopen(fn, "rb")) == NULL) {
fprintf(stderr, " * Unable to open \"%s\"\n", fn);
goto fail_1;
}
fprintf(stdout,
"Processing \"%s\"\n"
"Chunks of %d bytes of %d bits = %d bits\n",
fn,
CHUNK_CHAR, CHAR_BIT, CHUNK_CHAR * CHAR_BIT);
if (CHUNK_BITS != CHUNK_CHAR * CHAR_BIT) {
fprintf(stdout,
"%d bits chunk requested. Won't fit, trunkated to\n"
"%d * %d = %d\n"
"%d bits short.\n\n",
CHUNK_BITS,
CHUNK_CHAR, CHAR_BIT, CHUNK_BITS / CHAR_BIT * CHAR_BIT,
CHUNK_BITS - CHUNK_CHAR * CHAR_BIT);
}
while ((k = fread(buffer, 1, CHUNK_CHAR, fh)) == CHUNK_CHAR) {
prnt_cshex(p, CHUNK_CHAR, HEX_WIDTH); /* Print as hex */
printf(" ");
prnt_csbytes(p, CHUNK_CHAR); /* Print as text */
putchar('\n');
}
if (!feof(fh)) {
fprintf(stderr, " * Never reached EOF;\n");
goto fail_close;
}
/* If input file does not fit in to CHUNK, report this */
if (k > 0) {
printf("%d byte tail: '", k);
prnt_csbytes(p, k);
printf("'\n");
}
fclose(fh);
return 0;
fail_close:
fclose(fh);
fail_1:
return 1;
}

You can try doing getchar() 8 times (each value returned by getchar is 1 byte = 8 bits) and then using atoh or something - I'm not even sure if atoh exists, but barring that do something like atoi followed by itoh.. or write your own function to convert it.

Related

Printing variable number of bytes using format strings with printf

Goal: Print variable number of bytes using a single format specifier.
Environment: x86-64 Ubuntu 20.04.3 LTS running in VM on an x86-64 host machine.
Example:
Let %kmagic be the format specifier I am looking for which prints k bytes by popping them from the stack and additing them to the output. Then, for %rsp pointing to a region in memory holding bytes 0xde 0xad 0xbe 0xef, I want printf("Next 4 bytes on the stack: %4magic") to print Next 4 bytes on the stack: deadbeef.
What I tried so far:
%khhx, which unfortunately just results in k-1 blank spaces followed by two hex-characters (one byte of data).
%kx, which I expected to print k/2 bytes interpreted as one number. This only prints 8 hex-characters (4 bytes) prepended by k - 8 blank spaces.
The number of non-blank characters printed matches the length of the format specifiers, i.e. the expected length of %hhx is 2, which is also the number of non-blank characters printed. The same holds for %x, which one expects to print 8 characters.
Question:
Is it possible to get the desired behavior? If so, how?
Is it possible to get the desired behavior? If so, how?
There does not exist printf format specifier to do what you want.
Is it possible
Write your own printf implementation that supports what you want. Use implementation-specific tools to create your own printf format specifier. You can take inspiration from linux kernel printk %*phN format speciifer.
It is not possible to using standard printf. You need to write your own function and customize the printf function.
http://www.gnu.org/software/libc/manual/html_node/Customizing-Printf.html
Example (simple dump):
int printdump (FILE *stream, const struct printf_info *info, const void *const *args)
{
const unsigned char *ptr = *(const unsigned char **)args[0];
size_t size = *(size_t*)args[1];
for(size_t i = 1; i <= size; i++)
{
fprintf(stream, "%02X%c", ptr[i-1], i % 8 ? ' ' : '\n');
}
return 1;
}
int printdumpargs (const struct printf_info *info, size_t n, int *argtypes)
{
if (n == 2)
argtypes[0] = PA_POINTER;
argtypes[1] = PA_INT;
return 2;
}
int main(void)
{
double x[4] = {456543645.6786e45, 456543654, 1e345, -345.56e67};
register_printf_function ('Y', printdump, printdumpargs);
printf("%Y\n", &x, sizeof(x));
}
As I see it is depreciated now (probably no one was using it)
https://godbolt.org/z/qKs6e1d9q
Output:
30 18 CB 5A EF 10 13 4B
00 00 00 A6 4D 36 BB 41
00 00 00 00 00 00 F0 7F
C4 5D ED 48 9C 05 60 CE
There is no standard conversion specifier for your purpose, but you can achieve your goal in C99 using an ancillary function and dynamic array:
#include <stdio.h>
char *dump_bytes(char *buf, const void *p, size_t count) {
const unsigned char *src = p;
char *dest = buf;
while (count --> 0) {
dest += sprintf(dest, "%.2X", *src++);
if (count)
*dest++ = ' ';
}
*dest = '\0'; // return an empty sting for an empty memory chunk
return buf;
}
int main() {
long n = 0x12345;
printf("n is at address %p with contents: %s\n",
(void *)&n,
dump_bytes((char[3 * sizeof(n)]){""}, &n, sizeof(n)));
return 0;
}
Output: n is at address 0x7fff523f57d8 with contents: 45 23 01 00 00 00 00 00
You can use a macro for simpler invocation:
#define DUMPBYTES(p, n) dump_bytes((char[3 * (n)]){""}, p, n)
int main() {
char *p = malloc(5);
printf("allocated 5 bytes at address %p with contents: %s\n",
p, DUMPBYTES(p, 5));
free(p);
return 0;
}

Wrong ciphertext length in c libgcrypt

So, i am trying to encrypt and decrypt a string, using libgcrypt library (version 1.8.7) on arch and at this moment i have tried 2 modes: CBC and GCM (not sure about GCM, so let's solve the CBC first), but the same problem appears.
I padd the string and then, encrypt it block by block. Sometimes, this happens chaotically by the way, the gcry_cipher_encrypt function returns wrong amount of bytes (5, 7, 11...), but if i understood correctly, the output should be 16 bytes (128 bits). The same thing happens with decryption, that i do the exact same way, block by block. I'm using the same GCRY handler with through out the encryption or decryption process and it feels like i'm really missing something... Here is an example, only encryption in CBC mode, to make it easier to find the problem.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
// Define cipher details
#define GCRY_CIPHER GCRY_CIPHER_AES256
#define GCRY_C_MODE GCRY_CIPHER_MODE_CBC
char * encrypt_block(gcry_cipher_hd_t handler, unsigned char * key, unsigned char * input) {
size_t key_length = 32;
size_t blk_length = 16;
// Encryption result variable
unsigned char * enc = (char *) calloc(16, sizeof(char));
// Error variable
gcry_error_t err = 0;
// Set key
err = gcry_cipher_setkey(handler, key, key_length);
if (err) {
printf("Couldn't set the key!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
// Start encryption process
err = gcry_cipher_encrypt(handler, enc, blk_length, input, blk_length);
if (err) {
printf("Couldn't encrypt!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
if (strlen(enc) != 16) {
printf("\n\nCORRUPTED BLOCK!\n\n");
}
// Printing the block result
printf("\nENC BLOCK:\t%d\t", strlen(enc));
for (unsigned short int i = 0; i < strlen(enc); ++i) {
printf("%X ", enc[i]);
}
printf("\n");
return enc;
}
int main() {
// Creating basic variables
unsigned char * input = (char *) calloc(2048, sizeof(char));
unsigned char * key = (char *) calloc(32, sizeof(char));
unsigned char * iv = (char *) calloc(16, sizeof(char));
// Taking user input
printf("Input (2048 max): ");
scanf(" %[^\n]", input);
printf("Key (32 max): ");
scanf(" %[^\n]", key);
printf("RAW DATA:\n\tinput: %d\t%s\n\tkey: %d\t%s\n\n", strlen(input), input, strlen(key), key);
// Create GCRY handler
gcry_cipher_hd_t handler;
gcry_error_t err = 0;
// Initialize cipher handler
err = gcry_cipher_open(&handler, GCRY_CIPHER, GCRY_C_MODE, 0);
if (err) {
printf("Couldn't initialize the cipher!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
// Add padding to the input
if ((strlen(input) % 16) != 0) {
for (unsigned short int i = 0; i < (((strlen(input) / 16) * 16) - strlen(input)); ++i) {
strcat(input, "X");
}
}
// Add padding to the key
if (strlen(key) < 32) {
for (unsigned short int i = strlen(key); i < 32; ++i) {
key[i] = 0x0058;
}
}
// Generate random IV
char charset[] = "abcdefghijklmnopqrstuvwxyz0123456789";
unsigned short int iv_size = 16;
for (unsigned short int i = 0; i < iv_size; ++i) {
unsigned short int index = rand() % (unsigned short int) (sizeof charset - 1);
iv[i] = charset[index];
}
// Set the IV
err = gcry_cipher_setiv(handler, iv, 16);
if (err) {
printf("Couldn't set the IV!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
printf("ENC DATA:\n\tinput: %d\t%s\n\tkey: %d\t%s\n\tiv: %d\t%s\n\n", strlen(input), input, strlen(key), key, strlen(iv), iv);
// Create encryption variables
unsigned char * input_buffer = (char *) calloc(16, sizeof(char));
unsigned char * enc_buffer = (char *) calloc(16, sizeof(char));
unsigned char * out = (char *) calloc(strlen(input), sizeof(char));
// Start encryption process block by block
for (unsigned short int i = 0; i < (strlen(input) / 16); ++i) {
// Create a new block
for (unsigned short int j = 0; j < 16; ++j) {
input_buffer[j] = input[(i * 16) + j];
}
printf("\nENC INPUT:\t%d\t%s\n", strlen(input_buffer), input_buffer);
// Check if this is a final round
if (i == ((strlen(input) / 16) - 1)) {
err = gcry_cipher_final(handler);
}
// Start encrypting the block
enc_buffer = encrypt_block(handler, key, input_buffer);
// Adding up the block to the out result
strcat(out, enc_buffer);
memset(input_buffer, 0, 16);
memset(enc_buffer, 0, 16);
}
// Print the encryption result
printf("\n\nENC RESULT:\n\t%d\n\t", strlen(out));
for (unsigned short int i = 0; i < strlen(out); ++i) {
printf("%X ", out[i]);
}
printf("\n");
gcry_cipher_close(handler);
}
Output:
Input (2048 max): This string is made for testing the program
Key (32 max): hey my password
RAW DATA:
input: 43 This string is made for testing the program
key: 15 hey my password
ENC DATA:
input: 48 This string is made for testing the programXXXXX
key: 32 hey my passwordXXXXXXXXXXXXXXXXX
iv: 16 t8jhfhkm7bo5ohxw
ENC INPUT: 16 This string is m
ENC BLOCK: 16 2 BF AA A0 1 7C A8 77 DA 4A 5A 72 29 EB FA F6
ENC INPUT: 16 ade for testing
ENC BLOCK: 16 41 BA CE 61 8A E3 F4 89 8A 46 50 2 47 5 11 A4
ENC INPUT: 16 the programXXXXX
CORRUPTED BLOCK!
ENC BLOCK: 12 AE D6 92 D2 5A AF 85 CB 57 2 1B 93
ENC RESULT:
44
2 BF AA A0 1 7C A8 77 DA 4A 5A 72 29 EB FA F6 41 BA CE 61 8A E3 F4 89 8A 46 50 2 47 5 11 A4 AE D6 92 D2 5A AF 85 CB 57 2 1B 93
I am really sorry for this mess, it's just me going crazy at this point, it seems like the solution is so simple, but i just can't get it.
strlen does not tell you anything about your output buffer's length. Your output buffer is, in fact, always the same length. There's no need to test its length because libgcrypt has no way of modifying its length.
If you want to understand why strlen is returning "chaotic" values, you need to understand what strlen is intended to do. strlen is intended to operate on a C-style (null-terminated) string, not on arbitrary bytes. Strings in C are stored as arrays of characters ending with a '\0' (0x00) character. This is the null terminator. This is how the length of C-strings can be determined.
// example implementation to explicate the concept
size_t strlen(const char *s) {
size_t i = 0;
while (s[i] != '\0')
++i;
return i;
}
When you apply strlen to arbitrary bytes, the results are nonsensical. It is perfectly possible for your binary ciphertext to contain the byte 0x00 anywhere. It could appear at the beginning or anywhere in the middle. It could appear several times. Or it could never appear, in which case you would get a fatal segmentation fault. Wherever 0x00 happens to first appear in your ciphertext, that will be where strlen assumes it ends. The behavior appears "chaotic" because encryption produces random-seeming data, so the distribution of 0x00 within that data is also random-seeming.
PS: You don't need to reset the key every time you encrypt a block.

Difference between writing an integer in a HEX from a real

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&half;×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.

printing a 64bit value in C

I am using ubuntu x86_64 machine and trying to set the bit position corresponding to the character in string.
Character can a-z or A-Z, so I have kept a 64 bit vector.
long unsigned int vector = 0x0;
char *getunqchar(char a[]) {
char str[30];
int i;
long unsigned int t, test = 0;
for (i = 0; i < strlen(a) - 1; i++) {
t = (long unsigned int)(a[i]) - 65;
printf("t is %ld", t);
test = (long unsigned int)(1 << t);
vector = (vector ) | test;
printf("vec is %ld %ld \n", (long unsigned int)vector, (long unsigned int)test);
}
}
int main() {
int i = 0;
char name[30], *temp;
int cnt[52], t;
memset(cnt, 0, sizeof(cnt));
printf("vec is %lx", vector);
printf("Enter the string name: ");
fgets(name, sizeof(name), stdin);
temp = getunqchar(name);
}
when I input like below:
Enter the string name: mAn
t is 44vec is 4096 4096
t is 0vec is 4097 1
t is 45vec is 12289 8192
t value is 44, I expect output as 2^44 but I am getting 2^12.
44 is 32 + 12. It seems to be some issue because of 64 bit. But I am not getting. Any help is appreciated.
1 << t is evaluated as int, use 1UL << t to evaluate as unsigned long.

Get rid of following binary numbers but keep bitsize

A bit new to C programming but I've made a binary mask in my program and there are following 0 on the wrong side.
Hex: 0x61
Binary Result: 0110000100000000
Binary Want: 0000000001100001
Is there a way I could shift them down to start from LSB instead?
Back of my mind is maybe, inverse the masking? Just a hunch.
Here's my function:
void printBin(char Key)
{
int count;
int bits = 16;
unsigned int mask = 1 << --bits;
for(count = 0; count <= bits; count++)
{
if( Key & mask)
{
printw("1");
}
else
{
printw("0");
}
Key <<= 1;
}
}
When you are trying to print a binary string, when you loop over your number shifting the bits as you are, you end up with the bits in reverse order. While you can simply print the binary representation, it is far easier to save binary representation to a character string (so you can save it in the correct order) and return a pointer to a statically declared string.
The 3 functions below (1) binstr returns a simple binary string containing only the number of bits that make up the representation; (2) binpad returns a binary string padded to sz bits (so you can print all 64-bits of a 64-bit number, including the leading zeros) and (3) binfmt that returns a string padded to sz bits in szs bit groups separated by sep character.
To use the functions, simply declare the constants that tell whether your computer is 32/64 bit, that will set the number of BITS_PER_LONG along with CHAR_BIT (generally 8). Their use is shown below in the example:
#include <stdio.h>
#include <stdlib.h>
/* CHAR_BIT */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* BUILD_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
/* (note: adjust as required if not using x86/x86_64) */
char *binstr (unsigned long n);
char *binpad (unsigned long n, size_t sz);
char *binfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep);
int main (int argc, char **argv) {
unsigned long v = argc > 1 ? strtoul (argv[1], NULL, 10) : 237;
unsigned long sz = argc > 2 ? strtoul (argv[2], NULL, 10) : sizeof v * CHAR_BIT;
unsigned long szs = argc > 3 ? strtoul (argv[3], NULL, 10) : CHAR_BIT;
/* print 16-bit binary representation */
printf ("\n binstr (%lu)\n %s\n", v, binstr (v));
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz/4, binpad (v, sz/4));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz/4, (unsigned)szs/2, '-', binfmt (v, sz/4, szs/2, '-'));
/* print 32-bit binary representation */
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz/2, binpad (v, sz/2));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz/2, (unsigned)szs, '-', binfmt (v, sz/2, szs, '-'));
/* print 64-bit binary representation */
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz, binpad (v, sz));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz, (unsigned)szs, '-', binfmt (v, sz, szs, '-'));
return 0;
}
/** simple return of binary string */
char *binstr (unsigned long n)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
if (!n) {
*s = '0';
return s;
}
for (; n; n >>= 1)
*--p = (n & 1) ? '1' : '0';
return p;
}
/** returns pointer to binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (unsigned long n, size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (n>>i & 1) ? '1' : '0';
return p;
}
/** returns pointer to formatted binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *binfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep) {
static char s[BITS_PER_LONG * 2 + 1] = {0};
char *p = s + BITS_PER_LONG;
unsigned char i;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (n >> i & 1) ? '1' : '0';
}
return p;
}
Output
$ ./bin/binstrtst
binstr (237)
11101101
binpad (237, 16)
0000000011101101
binfmt (237, 16, 4, -)
0000-0000-1110-1101
binpad (237, 32)
00000000000000000000000011101101
binfmt (237, 32, 8, -)
00000000-00000000-00000000-11101101
binpad (237, 64)
0000000000000000000000000000000000000000000000000000000011101101
binfmt (237, 64, 8, -)
00000000-00000000-00000000-00000000-00000000-00000000-00000000-11101101
Let me know if you have any questions. Hope this helps. You can test with your 0x61 (decimal 97), e.g.:
$ ./bin/binstrtst 97
binstr (97)
1100001
binpad (97, 16)
0000000001100001
binfmt (97, 16, 4, -)
0000-0000-0110-0001
binpad (97, 32)
00000000000000000000000001100001
binfmt (97, 32, 8, -)
00000000-00000000-00000000-01100001
binpad (97, 64)
0000000000000000000000000000000000000000000000000000000001100001
binfmt (97, 64, 8, -)
00000000-00000000-00000000-00000000-00000000-00000000-00000000-01100001
If you are always expecting only 8-bits, you could use right shift operator, something like this:
a = a >> 8;
this will shift the bits to its right by 8 bits.
You are applying a 16bit mask on an 8bit char. If you cast it to an int before you do your bit operations it will work as you expect it to.
void printBin(char key_8) // key_8: 0x01100001
{
int key_16 = key_8; // key_16: 0x0000000001100001
int count;
int bits = 16;
unsigned int mask = 1 << --bits; // mask: 0x1000000000000000
for(count = 0; count <= bits; count++)
{
if(key_16 & mask)
{
printw("1");
}
else
{
printw("0");
}
key_16 <<= 1;
}
}

Resources