I'm learning how numbers are represented in memory. I want to know how to print the actual representation (binary or hexadecimal) in memory of some int and float variables.
I'd like to see what happens with that numbers when adding or subtracting it causes overflow, for example.
How can I access memory and print it?
You would need to assign a pointer to the variable in question to a char *, and treat it as an array of bytes of length sizeof(variable). Then you can print each byte in hex using the %X format specifier to printf.
You can define a function like this:
void print_bytes(void *ptr, int size)
{
unsigned char *p = ptr;
int i;
for (i=0; i<size; i++) {
printf("%02hhX ", p[i]);
}
printf("\n");
}
And call it like this:
int x = 123456;
double y = 3.14;
print_bytes(&x, sizeof(x));
print_bytes(&y, sizeof(y));
... to print the actual representation (binary ...
To convert any variable/object to a string that encodes the binary form uses a helper function that converts memory into a "binary" string. This method also handles function pointers. Uses C99 or later.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
// .... compound literal .......
#define VAR_TO_STR_BIN(x) obj_to_bin((char [sizeof(x)*CHAR_BIT + 1]){""}, &(x), sizeof (x))
char *obj_to_bin(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;
while (i-- > 0) {
*s++ = ((*p >> i) & 1) + '0';
}
}
*s = '\0';
return dest;
}
int main(void) {
int i = 42;
double d = 3.1415926535897932384626433832795;
printf("Sample\ndouble pi:%s\nint 42:%s\n", VAR_TO_STR_BIN(d), VAR_TO_STR_BIN(i) );
return 0;
}
Output (Note: depending in endian-ness, results may vary)
Sample
double pi:0100000000001001001000011111101101010100010001000010110100011000
int 42:00000000000000000000000000101010
This approach is easy to adapt to hexadecimal form.
Let's say you have a int variable called memory. Make sure you see how many bits it is; for many processors an int is 32 bits as well as a memory address. So you need to loop through each bit, like this:
unsigned int memory = 1234;
for (int i = 0; i < 32; i++)
{
printf("%d ", memory >> i & 1);
}
This simple method ORs each bit with 1 and shifts each bit by 1.
#include <stdio.h>
#include <stdlib.h>
void print_bits ( void* buf, size_t size_in_bytes )
{
char* ptr = (char*)buf;
for (size_t i = 0; i < size_in_bytes; i++) {
for (short j = 7; j >= 0; j--) {
printf("%d", (ptr[i] >> j) & 1);
}
printf(" ");
}
printf("\n");
}
int main ( void )
{
size_t n;
scanf("%d", &n);
print_bits(&n, sizeof(n));
return 0;
}
This prints bits of the specified object (n here) with the specified size (in bytes).
#dbush, #Anton, I mixed your codes. It's okay?
#include <stdio.h>
#include <stdlib.h>
void print_bytes( void *ptr, size_t size ) ;
int main( void )
{
int x = 123456 ;
double y = 3.14 ;
print_bytes( &x, sizeof(x) ) ;
print_bytes( &y, sizeof(y) ) ;
return 0 ;
}
void print_bytes( void *ptr, size_t size )
{
//char *buf = (char*) ptr;
unsigned char *p = ptr ;
for( size_t i = 0; i < size; i++ )
{
printf( "%02hhX ", p[i] ) ;
}
printf( "\n" ) ;
for( size_t i = 0; i < size; i++ )
{
for( short j = 7; j >= 0; j-- )
{
printf( "%d", ( p[i] >> j ) & 1 ) ;
}
printf(" ");
}
printf("\n");
}
Call print_bits(memory address of variable, size of variable in byte).
void print_bits(void *ptr, int size) //ptr = memory address of variable, size = size of variable in byte
{
long long *ch = ptr;
int size_bits = size * 8;
for(int i = size_bits-1; i>=0; i--){
printf("%lld", *ch >> i & 1) ;
}
}
It has been tested successfully, working with any variable of less than or equal to 64 bits. This will probably work correctly with variables with other sizes (Not Tested).
Calling:
double d = -7.92282286274e+28;
print_bits(&d, sizeof(d));
Output:
1100010111110000000000000000000011100000000000000000000100010111
Related
I have an int, and I need to split it to a char array, so 2 chars in each array position. After that, I need to do the opposite process. This is the best I could come up with, but I still couldn't make it work. Any suggestions?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int length = 10968;
int bytesNeeded = sizeof(length) / 2;
char *controlPacket = (char*)malloc(sizeof(char*)*bytesNeeded);
for (int i = 0; i < bytesNeeded; i++)
{
controlPacket[i] = (length >> (8* i));
}
int newSize = 0;
for (int i = 0; i < bytesNeeded; i++)
{
newSize += (controlPacket[i] << (8 * i));
}
printf("Newsize is: %d\n", newSize);
}
Change the variables that you're performing bitwise operations on to unsigned, and also mask the result of shifting before assigning to the array. Otherwise, you get overflow, which causes incorrect results (maybe undefined behavior, I'm not sure).
You also shouldn't divide sizeof(length) by 2. It will work for values that only use the low order half of the number, but not for larger values; e.g. if you use length = 1096800; the result will be 48824.
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int length = 10968;
int bytesNeeded = sizeof(length);
unsigned char *controlPacket = malloc(sizeof(unsigned char)*bytesNeeded);
for (int i = 0; i < bytesNeeded; i++)
{
controlPacket[i] = (length >> (8* i) & 0xff);
}
unsigned int newSize = 0;
for (int i = 0; i < bytesNeeded; i++)
{
newSize += (controlPacket[i] << (8 * i));
}
printf("Newsize is: %d\n", newSize);
free(controlPacket);
}
I want to make a function that converts unsigned char to unsigned int and store it into an array. However, this ends up with an error that says
passing argument 1 of 'sprintf' from incompatible pointer type.
int main(void) {
unsigned char key[16] = "1234567812345678";
phex(key, 16); //store into an array here
}
uint64_t* phex(unsigned char* string, long len)
{
uint64_t hex[len];
int count = 0;
for(int i = 0; i < len; ++i) {
count = i * 2;
sprintf(hex + count, "%.2x", string[i]);
}
for(int i = 0; i < 32; i++)
printf(hex[i]);
return hex;
}
As comments have already said, you have problems in your code...
First of all sprintf function does totally opposite thing of what you want/expect it to do. Next, you create a local variable in your function, and return pointer to it.. As soon as function exits, pointer is invalid. Third problem I see is that you never assign return value to anything...
Proposition on how to fix your code:
unsigned* phex(unsigned char* string, long len);
int main(void) {
int i;
unsigned char key[16] = "1234567812345678";
unsigned* ints = phex(key,16); //store into an array here
for(i = 0; i < 16; i++)
printf("%d ", ints[i]);
//never forget to deallocate memory
free(ints);
return 0;
}
unsigned* phex(unsigned char* string, long len)
{
int i;
//allocate memory for your array
unsigned* hex = (unsigned*)malloc(sizeof(unsigned) * len);
for(i = 0; i < len; ++i) {
//do char to int conversion on every element of char array
hex[i] = string[i] - '0';
}
//return integer array
return hex;
}
question of curiosity
suppose I have:
int main(void)
{
char str[32];
for (i = 0; i < 32; i++)
str[i] = 0;
}
but I want to do it 4x faster
int main(void)
{
char str[32];
for (i = 0; i < 32 / 4; i += 4)
str[i] = (int)0;
}
I expect that the whole array will be filled with zeros.
but array is not filled by zeroes
my questions: why array not filled by zeroes? how to fill array per int blocks? my question is Research for c feature, how to tell the compiler - write blocks of 4 bytes, ie integer registers, it will reduce the number of memory accesses by 4 times, on x64 processors reduce 8 times
thanks for all, follows work well:
int main(int argc, char *argv[])
{
char str[32];
int i;
for (i = 0; i < 32; i++)
str[i] = 12;
for (i = 0; i < 32 / sizeof(int); i++)
((int *) str)[i] = 0;
printf("%d\n", i);
for (i = 0; i < 32; i++)
printf("%d\n", str[i]);
return 0;
}
The correct and fastest way is to initialize the array to zero
char str[32] = { 0 } ;
If you want to set the array to zero afterwards, then use memset and enable compiler optimization and intrinsic functions, and the compiler will figure out the fastest way to zero the array.
memset( str , 0 , sizeof( str ) ) ;
As pointed out by #user2501, initializing to {0} or using memset is the fastest and correct way.
If you are tempted to use something like ((int *)str)[i] = 0, do not, this can result in unaligned access.
As an alternative to memset, in C99 (and assuming that int is 4 bytes) you can use the type punning feature of unions:
#include <stdio.h>
typedef union {
char as_string[32];
int as_int[8];
} foo;
int main(void)
{
foo x;
int i;
for (i = 0; i < 8; i++)
x.as_int[i] = 0;
for (i = 0; i < 32; i++)
printf("%d", x.as_string[i]);
printf("\n");
return 0;
}
Output:
00000000000000000000000000000000
Seems that you are forced to use pointers and casts, this version uses the heap in order to allocate str on an address properly aligned for int:
#include <stdio.h>
#include <stdlib.h> /* malloc, free */
#include <stdint.h> /* intptr_t (pointer arithmetic using modulo division) */
#define MAX 32
int main(void)
{
size_t i, align;
char *ptr, *str;
align = __alignof__(int);
ptr = malloc(MAX + align); /* MAX + max align distance */
str = ptr + align - (intptr_t)ptr % align; /* now str is properly aligned */
for (i = 0; i < MAX / sizeof(int); i++)
((int *)str)[i] = 0;
for (i = 0; i < MAX; i++)
printf("%d\n", str[i]);
free(ptr);
return 0;
}
Note that __alignof__ is a gcc extension, change to __alignof if you are under Visual Studio or _Alignof if you are comfortable with C11.
You have to cast the pointer as the int, not the value:
int main(void)
{
char str[32];
for (i = 0; i < 32/sizeof(int); i++)
((int *) str)[i] = 0xAABBCCDD; //Be careful of Endianness
}
Alternatively:
int i;
union block_fill
{
char arr[24];
int iarr[6];
};
union block_fill block_arr;
for(i=0; i<6; i++)
block_arr.iarr[i] = 0x11223344;
for(i=0; i<24; i++)
printf("%x", block_arr.arr[i]);
I want to convert array of bytes bytes1 (little endian), 2 by 2, into an array of short integers, and vice versa . I expect to get final array bytes2, equal to initial array bytes1. I have code like this:
int i = 0;
int j = 0;
char *bytes1;
char *bytes2;
short *short_ints;
bytes1 = (char *) malloc( 2048 );
bytes2 = (char *) malloc( 2048 );
short_ints = (short *) malloc( 2048 );
for ( i=0; i<2048; i+=2)
{
short_ints[j] = bytes1[i+1] << 8 | bytes1[i] ;
j++;
}
j = 0;
for ( i=0; i<2048; i+=2)
{
bytes2[i+1] = (short_ints[j] >> 8) & 0xff;
bytes2[i] = (short_ints[j]) ;
j++;
}
j = 0;
Now, can someone tell me why I haven't got bytes2 array, completely the same as bytes1 ? And how to do this properly?
Suggest 2 functions. Do all combining and extraction as unsigned to remove issues with the sign bit in short and maybe char.
The sign bit is OP's code biggest problem. short_ints[j] = bytes1[i+1] << 8 | bytes1[i] ; likely does a sign extend with bytes1[i] conversion to int.
Also (short_ints[j] >> 8) does a sign extend.
// Combine every 2 char (little endian) into 1 short
void charpair_short(short *dest, const char *src, size_t n) {
const unsigned char *usrc = (const unsigned char *) src;
unsigned short *udest = (unsigned short *) dest;
if (n % 2) Handle_OddError();
n /= 2;
while (n-- > 0) {
*udest = *usrc++;
*udest += *usrc++ * 256u;
udest++;
}
}
// Break every short into 2 char (little endian)
void short_charpair(char *dest, const short *src, size_t n) {
const unsigned short *usrc = (const unsigned short *) src;
unsigned char *udest = (unsigned char *) dest;
if (n % 2) Handle_OddError();
n /= 2;
while (n-- > 0) {
*udest++ = (unsigned char) (*usrc);
*udest++ = (unsigned char) (*usrc / 256u);
usrc++;
}
}
int main(void) {
size_t n = 2048; // size_t rather than int has advantages for array index
// Suggest code style: type *var = malloc(sizeof(*var) * N);
// No casting of return
// Use sizeof() with target pointer name rather than target type.
char *bytes1 = malloc(sizeof * bytes1 * n);
Initialize(bytes, n); //TBD code for OP-best to not work w/uninitialized data
// short_ints = (short *) malloc( 2048 );
// This is weak as `sizeof(short)!=2` is possible
short *short_ints = malloc(sizeof * short_ints * n/2);
charpair_short(short_ints, bytes1, n);
char *bytes2 = malloc(sizeof * bytes2 * n);
short_charpair(bytes2, short_ints, n);
compare(bytes1, bytes2, n); // TBD code for OP
// epilogue
free(bytes1);
free(short_ints);
free(bytes2);
return 0;
}
Avoided the union approach as that is platform endian dependent.
Here's a program that demonstrates that you are experiencing the problem associated with bit-shifting signed integral values.
#include <stdio.h>
#include <stdlib.h>
void testCore(char bytes1[],
char bytes2[],
short short_ints[],
int size)
{
int i = 0;
int j = 0;
for ( i=0; i<size; i+=2)
{
short_ints[j] = bytes1[i+1] << 8 | bytes1[i] ;
j++;
}
j = 0;
for ( i=0; i<size; i+=2)
{
bytes2[i+1] = (short_ints[j] >> 8) & 0xff;
bytes2[i] = (short_ints[j]) ;
j++;
}
for ( i=0; i<size; ++i)
{
if ( bytes1[i] != bytes2[i] )
{
printf("%d-th element is not equal\n", i);
}
}
}
void test1()
{
char bytes1[4] = {-10, 0, 0, 0};
char bytes2[4];
short short_ints[2];
testCore(bytes1, bytes2, short_ints, 4);
}
void test2()
{
char bytes1[4] = {10, 0, 0, 0};
char bytes2[4];
short short_ints[2];
testCore(bytes1, bytes2, short_ints, 4);
}
int main()
{
printf("Calling test1 ...\n");
test1();
printf("Done\n");
printf("Calling test2 ...\n");
test2();
printf("Done\n");
return 0;
}
Output of the program:
Calling test1 ...
1-th element is not equal
Done
Calling test2 ...
Done
Udate
Here's a version of testCore that works for me:
void testCore(char bytes1[],
char bytes2[],
short short_ints[],
int size)
{
int i = 0;
int j = 0;
unsigned char c1;
unsigned char c2;
unsigned short s;
for ( i=0; i<size; i+=2)
{
c1 = bytes1[i];
c2 = bytes1[i+1];
short_ints[j] = (c2 << 8) | c1;
j++;
}
j = 0;
for ( i=0; i<size; i+=2)
{
s = short_ints[j];
s = s >> 8;
bytes2[i+1] = s;
bytes2[i] = short_ints[j] & 0xff;
j++;
}
for ( i=0; i<size; ++i)
{
if ( bytes1[i] != bytes2[i] )
{
printf("%d-th element is not equal\n", i);
}
}
}
It is tested with:
char bytes1[4] = {-10, 0, 25, -4};
and
char bytes1[4] = {10, -2, 25, 4};
Well, what you need is a UNION:
#include <stdio.h>
#include <string.h>
union MyShort {
short short_value;
struct {
char byte1;
char byte2;
};
};
int main(int argc, const char * argv[])
{
char a[4]="abcd";
char b[4]="1234";
short c[5]; c[4]=0;
union MyShort d;
for (int i = 0; i<4; i++) {
d.byte1 = a[i];
d.byte2 = b[i];
c[i] = d.short_value;
}//next i
printf("%s\n", (char*)c);
return 0;
}
the result should be a1b2c3d4.
I am attempting to write C functions with these two prototypes:
int extract_little (char* str, int ofset, int n);
int extract_big(char* str, int ofset, int n);
Now the general idea is I need to return a n byte integer in both formats starting from address str + ofset. P.S. Ofset doesn't do anything yet, I plan on (trying) to shuffle the memory via an offset once I figure out the little endian, for the big.
I'v trying to get it to output like this; for little endian, based off of i=0xf261a3bf;,
0xbf 0xa3 0x61 0xf2
int main()
{
int i = 0xf261a3bf;
int ofset = 1; // This isn't actually doing anything yet
int z;
for (z = 0; z < sizeof(i); z++){
printf("%x\n",extract_little((char *)&i,ofset, sizeof(i)));
}
return 0;
}
int extract_little(char *str,int offs, int n) {
int x;
for (x = 0; x < n; x++){
return str[x];
}
}
I'm not sure what else to try. I figured out the hard way that even thought I put it in a for loop I still can't return more than 1 value from the return.
Thanks!
unsigned long extract_little(const void *p, size_t offset, unsigned char n) {
unsigned long ret = 0;
for(size_t i = offset + n - 1; i >= offset; i--)
ret = (ret<<8) + ((char *)p)[i];
return ret;
}
unsigned long extract_big(const void *p, size_t offset, unsigned char n) {
unsigned long ret = 0;
for(size_t i = offset; i < (offset + n); i++)
ret = (ret<<8) + ((char *)p)[i];
return ret;
}
int main()
{
int i = 0xf261a3bf;
printf("%x\n", extract_little(&i, 0, sizeof(i)));
return 0;
}
Works (of course) only with n´s which are sizeof(unigned long) maximal.
And can be speed-improved, probably (depending on the compiler optimization).
With respect to your code: return does what it says, it returns from the function. The loop is never run for more than the first element.
With respect to the problem: Check out htonl and ntolh, except for exercise.