Printing error while accessing consecutive memory locations [duplicate] - c

This question already has answers here:
Printing hexadecimal characters in C
(7 answers)
Closed 9 years ago.
Following is a code to see how different data types are stored in memory.
#include <stdio.h>
void newline(void)
{
putchar('\n');
}
void showbyte(char *string, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", string+i, *(string+i));
}
int main()
{
int i = 12345;
float f = 1234.5;
double d = 1234.5;
char name[] = "12345";
showbyte((char *)&i, sizeof i);
newline();
showbyte((char *)&f, sizeof f);
newline();
showbyte((char *)&d, sizeof d);
newline();
showbyte((char *)&name, sizeof name);
return 0;
}
Output
0x7fff8a9ab2cc 0x39
0x7fff8a9ab2cd 0x30
0x7fff8a9ab2ce 0x00
0x7fff8a9ab2cf 0x00
0x7fff8a9ab2c8 0x00
0x7fff8a9ab2c9 0x50
0x7fff8a9ab2ca 0xffffff9a
0x7fff8a9ab2cb 0x44
0x7fff8a9ab2c0 0x00
0x7fff8a9ab2c1 0x00
0x7fff8a9ab2c2 0x00
0x7fff8a9ab2c3 0x00
0x7fff8a9ab2c4 0x00
0x7fff8a9ab2c5 0x4a
0x7fff8a9ab2c6 0xffffff93
0x7fff8a9ab2c7 0x40
0x7fff8a9ab2b0 0x31
0x7fff8a9ab2b1 0x32
0x7fff8a9ab2b2 0x33
0x7fff8a9ab2b3 0x34
0x7fff8a9ab2b4 0x35
0x7fff8a9ab2b5 0x00
The IEEE-754 representation for float 1234.5 is 0x449a5000, and for double 1234.5 is 0x40934A0000000000. When it printed the float and double variable contents, it shows a 4-byte content. ie,
0x7fff8a9ab2ca 0xffffff9a and
0x7fff8a9ab2c6 0xffffff93. But each memory location can store only 1-byte of data, then why does it happen?

unsigned is your friend in this case, because char is by default a signed type
if you change some of the types from char to unsigned char you get the correct result:
#include <stdio.h>
void newline(void)
{
putchar('\n');
}
void showbyte(unsigned char *string, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", string+i, *(string+i));
}
int main()
{
int i = 12345;
float f = 1234.5;
double d = 1234.5;
char name[] = "12345";
showbyte((unsigned char *)&i, sizeof i);
newline();
showbyte((unsigned char *)&f, sizeof f);
newline();
showbyte((unsigned char *)&d, sizeof d);
newline();
showbyte((unsigned char *)&name, sizeof name);
return 0;
}
In this case you get:
0x7fff5d5a98b8 0x39
0x7fff5d5a98b9 0x30
0x7fff5d5a98ba 0x00
0x7fff5d5a98bb 0x00
0x7fff5d5a98b4 0x00
0x7fff5d5a98b5 0x50
0x7fff5d5a98b6 0x9a
0x7fff5d5a98b7 0x44
0x7fff5d5a98a8 0x00
0x7fff5d5a98a9 0x00
0x7fff5d5a98aa 0x00
0x7fff5d5a98ab 0x00
0x7fff5d5a98ac 0x00
0x7fff5d5a98ad 0x4a
0x7fff5d5a98ae 0x93
0x7fff5d5a98af 0x40
0x7fff5d5a98a2 0x31
0x7fff5d5a98a3 0x32
0x7fff5d5a98a4 0x33
0x7fff5d5a98a5 0x34
0x7fff5d5a98a6 0x35
0x7fff5d5a98a7 0x00

Related

C - calculate address of pointer

I have program that put pointer p to some point and then calculate p-*p. The address of p is not specified in the program itself. How can I know what is p address?
typedef struct locals { int x; int y; } locals;
int main() {
locals Z; char *p;
Z.x = 0x00444342; Z.y = 0x01020304;
p = ((char *)&Z) + 4;
printf("%s\n", (p - *p));
}
I can explain how to calculate the address with few assumptions:
The size of int is 4 bytes
The system is little-endian
There are no 0 paddings in the struct
Thus the locals memory layout is so that the first 4 bytes (Z.x) are
byte[0] = 0x42
byte[1] = 0x43
byte[2] = 0x44
byte[3] = 0x00
and the next 4 bytes (Z.y) are
byte[0] = 0x04
byte[1] = 0x03
byte[2] = 0x02
byte[3] = 0x01
Now for p = ((cahr *)&Z) + 4, p would point to the beginning of Z plus 4 bytes, which brings us to byte[0] of Z.y.
Now about
printf("%s\n", (p - *p));
*p would be the value of the first byte of Z.y which is 0x04. And printf will get as the second argument address of Z.y - 4 bytes which is byte[0] of Z.x.
Thus the output of printf will be all characters till the first '\0' (which is the 3rd byte of Z.x):
ASCII 0x42 ASCII 0x43 ASCII 0x44:
BCD

String to ASCII Hex splitting in C

I am using C in Labwindows CVI 8.5.
I convert the float to ASCII Hex(this part is already done):
#include <stdio.h>
#include <string.h>
int main () {
char K_char[20], K_ASCII[20];
int a = 30; //30 degree Celsius
int i, len ;
float k = a + 273.15; //Temperature Celsius to Kelvin
sprintf(K_char, "%.2f", k); //Temperature K convert to char array
len = strlen(K_char);
for(i = 0; i<len; i++){
sprintf(K_ASCII+i*2, "%02X", K_char[i]); //char array convert to ASCII Hex
}
printf("%s\n", K_ASCII);
return(0);
}
The result from above code is 3330332E3135.
Now I want to extract each byte from above string like this :
a[0] = 0x33
a[1] = 0x30
a[2] = 0x33
a[3] = 0x2E
a[4] = 0x33
a[5] = 0x35
Can someone give me some advice?
Thanks for any help.
It seems you are over complicate it. You already have these values in K_char. Like
K_char[0] = 0x33
K_char[1] = 0x30
K_char[2] = 0x33
K_char[3] = 0x2E
K_char[4] = 0x31
K_char[5] = 0x35
Write a function that converts a single ASCII character '0' to '9' or 'A' to 'F' into the numeric equivalent.
Then loop over your ASCII format array like this:
size_t length = strlen(K_ASCII);
uint8_t hex [length/2+1];
for(size_t i=0; i<length/2; i++)
{
hex[i] = to_hex(K_ASCII[2*i]);
hex[i] <<= 4;
hex[i] += to_hex(K_ASCII[2*i+1]);
}

How to concatenate the hexadecimal data in an array in C

I have my data field as follows DATA = 0x02 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Now I want to concatenate this data as follows DATA = 0x01020304050607. How can I do it using C program. I found a program in C for concatenation of data in an array and the program is as follows:
#include<stdio.h>
int main(void)
{
int num[3]={1, 2, 3}, n1, n2, new_num;
n1 = num[0] * 100;
n2 = num[1] * 10;
new_num = n1 + n2 + num[2];
printf("%d \n", new_num);
return 0;
}
For the hexadecimal data in the array how can I manipulate the above program to concatenate the hexadecimal data?
You need a 64 bit variable num as result, instead of 10 as factor you need 16, and instead of 100 as factor, you need 256.
But if your data is provided as an array of bytes, then you can simply insert complete bytes, i.e. repeatedly shifting by 8 bits (meaning a factor of 256):
int main(void)
{
uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
unsigned long long num = 0;
for (int i=0; i<8; i++) {
num <<=8; // shift by a complete byte, equal to num *= 256
num |= data[i]; // write the respective byte
}
printf("num is %016llx\n",num);
return 0;
}
Output:
num is 0201020304050607
Lest say you have input like
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
If you want output like 0x0001020304050607, to store this resultant output you need one variable of unsigned long long type. For e.g
int main(void) {
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
int ele = sizeof(DATA)/sizeof(DATA[0]);
unsigned long long mask = 0x00;
for(int row = 0; row < ele; row++) {
mask = mask << 8;/* every time left shifted by 8(0x01-> 0000 0001) times */
mask = DATA[row] | mask; /* put at correct location */
}
printf("%016llx\n",mask);
return 0;
}
Here's some kind of hack that writes your data directly into an integer, without any bitwise operators:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint64_t numberize(const uint8_t from[8]) {
uint64_t r = 0;
uint8_t *p = &r;
#if '01' == 0x4849 // big endian
memcpy(p, from, 8);
#else // little endian
for (int i=7; i >= 0; --i)
*p++ = from[i];
#endif
return r;
}
int main() {
const uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
printf("result is %016llx\n", numberize(data));
return 0;
}
This does work and outputs this independently of the endianness of your machine:
result is 0201020304050607
The compile-time endianness test was taken from this SO answer.

Convert string decimal to hex decimal

How can I convert a string decimal to hex decimal and add them to char pointer? Why does the memcpy(value + 2, &value_value, value_length); not work, the result is 0x02 0x01 and not 0x02 0x01 0x4f.
#include <string.h> /* strlen */
#include <stdio.h> /* printf */
#include <stdint.h> /* int32_t */
#include <stdlib.h> /* strtol */
int main()
{
char value_type = 0x02;
char *value_value = "79"; /* Must convert to 4f */
char value_length;
int32_t num = strtol(value_value, NULL, 10);
if (num < 255)
value_length = 0x01;
else if (num < 65536)
value_length = 0x02;
else if (num < 16777216)
value_length = 0x03;
else if (num < 4294967295)
value_length = 0x04;
char *value = malloc(2 + value_length);
memcpy(value, &value_type, 1);
memcpy(value + 1, &value_length, 1);
memcpy(value + 2, &value_value, value_length);
/* expectation: 0x02 0x01 0x4f */
for (int i = 0; i < strlen(value); i++)
printf("%02x\n", value[i]);
return 0;
}
memcpy(value + 2, &value_value, value_length);
this expression copies value_length bytes from &value_value.
Given that it's declared as
char *value_value
&value_value is read as a pointer-to-a-pointer-to-a-char. So effectively you're reading the pointer value.
How to solve:
memcpy(value + 2, &num, value_length);
Another problem with your code:
you're using strlen(value) while value is not a null-terminated C-string. It's just an array of bytes that you fill with your data.
How to fix:
don't use strlen in this case, you know the size of the array: 2 + value_length. For clarity you may put it to a separate variable.
You are using wrong variable:
memcpy(value + 2, &num, value_length);
Also, you must not trait your value as string, as far as it uses binary value. Change your code to:
/* expectation: 0x02 0x01 0x4f */
int dumplen=len+2;
for (int i = 0; i < dumplen; i++)
printf("%02x\n", value[i]);
return 0;

Bit shift through an array

Say we have 8 bytes saved in an array like:
char array[8];
All of them are set to zero:
for (i = 0; i < 7; i++){
array[i] = 0x00;
}
How can shift a 1 from the first LSBit until the last MSBit like
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x04
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x10
.....................................
to
0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Here is what I've tried but the result isn't what I'm looking for:
uint8_t buffer[8];
int index = 0 ;
for ( index = 0; index < 8; index++){
buffer[index] = 0x00;
}
*buffer= 0x01;
for( index = 0 ; index < 64; index++){
*buffer = *buffer<< 1 ;
}
UPDATE
Here is an example of what I get:
#include <stdio.h>
int main (){
char buffer[2]={0x01, 0x00};
int i ;
for( i = 0 ; i < 12 ; i++){
printf("0x %2X %x \n",buffer[0], buffer[1]);
*buffer <<= 1;
}
}
And the output is:
0x 1 0
0x 2 0
0x 4 0
0x 8 0
0x 10 0
0x 20 0
0x 40 0
0x FFFFFF80 0
0x 0 0
0x 0 0
0x 0 0
0x 0 0
I really don't understand the 0xFFFFFF80!
What byte that is "LS byte" and which one that is "MS byte" is perhaps not obvious. An array of 8 characters is always allocated in memory like this:
LS address MS address
Byte 0, ... Byte 7
This is true for all CPUs. So the 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 in your question doesn't make any sense: you have misunderstood how arrays are allocated in memory. What you have shown in your examples is how to take bit 0 in the ms byte and left shift it to bit 7 in the ls byte. Which probably doesn't make any sense.
However, if you would attempt to print this array as a 64 bit integer, the value array[0]=1 would give you 0000000000000001 on a little endian machine, but 0100000000000000 on a big endian machine. But nothing in your question states that you want to print the array as a 64 bit value, so it is not clear what you are actually asking.
Try this:
#include <stdio.h>
#include <stdint.h>
typedef union
{
uint8_t array[8];
uint64_t u64;
} my_type;
int main()
{
my_type t = {0};
t.array[0] = 0x01;
// how the array is actually allocated:
for(int i=0; i<8; i++) // 0100000000000000 on all machines
{
printf("%.2X", t.array[i]);
}
printf("\n");
// how the array turns out when printed as a 64 bit int:
printf("%.16llX\n", t.u64); // 0000000000000001 little endian
// perhaps what you intended to do, on a little endian machine
t.u64 <<= 63;
printf("%.16llX\n", t.u64); // 8000000000000000 little endian
return 0;
}
As per harold's comment, just carry the 1. So, to shift one place:
uint8_t carry = 0;
for( index = 7 ; index >= 0; index--){
uint8_t nextCarry = buffer[index] >> 7;
buffer[index] = (buffer[index] << 1) | carry;
carry = nextCarry;
}
EDIT: also, it strikes me that your CPU almost certainly has a native 64-bit type. In which case just use a uint64_t directly rather than an array of bytes and perform variable <<= 1;.
I'm not sure if this is what you want, but the following code does at least what was posed in the question:
uint8_t temp = buffer[0];
printf("Initial Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
// Left Shift until highest bit that is 1 is found
while(!(temp & 0x80))
temp = temp<<1;
// Re-assignments
buffer[7] = temp;
buffer[0] = 0;
printf("\nFinal Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
In true sense, this is not "shifting entirely through the buffer", but if you could provide more details on what you wish to accomplish, this code could be modified accordingly.
Since you are trying to treat your char array as a single 64 bit object, why not use an actual 64 bit object?
union
{
char array[8];
uint64_t all;
} data;
int index = 0;
data.all = 0;
data.array[0] = 0x01;
for(index = 0; index < 64; index++)
{
data.all = data.all << 1;
}
Note that this assumes that you are working on a little endian machine.
So I've done it , maybe it's not the best way but it works, and if someone needs I'll be glade to share it :
#include <stdio.h>
#include <stdint.h>
int main (){
uint8_t buffer[8];
char* pChar = buffer;
uint8_t carry =0x01;
int i = 0;
short lock [8];
// Array initialization
for ( i =0 ; i <8; i++){
buffer[i] =0x00;
lock[i] = 0x00;
}
pChar =buffer;
for( i = 0 ; i < 64 ; i++){
*pChar = carry;
printf(" 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x \n",buffer[0], buffer[1],buffer[2],buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
carry<<=1;
if( i>=7 && lock[0]==0){
*pChar = 0;
pChar++;
carry=0x01;
lock[0]=1;
}else if ( i>=15 && lock[1]==0) {
*pChar = 0;
pChar++;
carry=0x01;
lock[1]=1;
}else if( i>= 23 && lock[2]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[2] =1;
}
else if( i>= 31 && lock[3]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[3] =1;
}
else if( i>=39 && lock[4]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[4] =1;
}
else if( i>= 47 && lock[5]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[5] =1;
}
else if( i>= 55 && lock[6]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[6] =1;
}
}
thanks for your help !

Resources