I have a question about pointers in C. For example:
int data[SIZE] = {2,4,5,1,0};
int *p = &data[2];
int **s=&p;
p++;
printf("%p ", *s);
Is here the pointer *s equal to *p, i.e is the adress of *s equal to *p?
*It may be an easy question, but we didnt spend enough time learning C
After the declarations, you have the following:
s == &p // int ** == int **
*s == p == &data[2] // int * == int * == int *
**s == *p == data[2] == 5 // int == int == int == int
After p++:
*s == p == &data[3]
**s == *p == data[3] == 1
If you run
int data[5] = {2,4,5,1,0};
int *p = &data[2];
int **s=&p;
p++;
int data[5] = {2,4,5,1,0};
int *p = &data[2];
int **s=&p;
p++;
printf("*p: %d \n", *p);
printf("&p: %p \n", &p);
printf("s: %p \n", s);
printf("*s: %p \n", *s);
printf("**s: %d \n", **s);
you'll get:
*p: 1
&p: 0x7ffc69a74650
s: 0x7ffc69a74650
*s: 0x7ffc69a7466c
**s: 1
Which shows that the value pointed by both *p and **s is the same (1), also &p == s but &p and *s are not the same, as there's an extra "step".
Here's a possible execution of your program:
int data[SIZE] = {2,4,5,1,0};
// your memory looks like this:
// Address (name) -> Value
// 0x80 (data[0]) -> 2
// 0x84 (data[1]) -> 4
// 0x88 (data[2]) -> 5
// 0x8C (data[3]) -> 1
// 0x90 (data[4]) -> 0
int *p = &data[2];
// 0x80 (data[0]) -> 2
// 0x84 (data[1]) -> 4
// 0x88 (data[2]) -> 5
// 0x8C (data[3]) -> 1
// 0x90 (data[4]) -> 0
// 0xC0 (p) -> 0x88
int **s=&p;
// 0x80 (data[0]) -> 2
// 0x84 (data[1]) -> 4
// 0x88 (data[2]) -> 5
// 0x8C (data[3]) -> 1
// 0x90 (data[4]) -> 0
// 0xC0 (p) -> 0x88
// 0xD8 (s) -> 0xC0
p++;
// 0x80 (data[0]) -> 2
// 0x84 (data[1]) -> 4
// 0x88 (data[2]) -> 5
// 0x8C (data[3]) -> 1
// 0x90 (data[4]) -> 0
// 0xC0 (p) -> 0x8C
// 0xD8 (s) -> 0xC0
printf("%p ", *s); //Will print 0x8C
So no, *s (the value pointed by s) won't be equal to *p (the value pointed by p) but to p (the address of the p pointer)
Related
is the number 1 stored in memory as 00000001 00000000 00000000 00000000?
#include <stdio.h>
int main()
{
unsigned int a[3] = {1, 1, 0x7f7f0501};
int *p = a;
printf("%d %p\n", *p, p);
p = (long long)p + 1;
printf("%d %p\n", *p, p);
char *p3 = a;
int i;
for (i = 0; i < 12; i++, p3++)
{
printf("%x %p\n", *p3, p3);
}
return 0;
}
Why is 16777216 printed in the output:
An integer is stored in memory in different ways on different architectures. Most commons ways are called little-endian and big-endian byte ordering.
See Endianness
(long long)p+1
|
v
Your memory: [0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ...]
You increment p not like pointer but as a long long number, so it does not point to next integer but the next byte. So you will get 0x00, 0x00, 0x00, 0x01 which translates to 0x1000000 (decimal 16777216) in a little-endian arch.
Something to play with (assuming int is 32 bits wide):
#include <stdio.h>
#include <stdbool.h>
typedef union byte_rec {
struct bit_rec {
bool b0 : 1;
bool b1 : 1;
bool b2 : 1;
bool b3 : 1;
bool b4 : 1;
bool b5 : 1;
bool b6 : 1;
bool b7 : 1;
} bits;
unsigned char value;
} byte_t;
typedef union int_rec {
struct bytes_rec {
byte_t b0;
byte_t b1;
byte_t b2;
byte_t b3;
} bytes;
int value;
} int_t;
void printByte(byte_t *b)
{
printf(
"%d %d %d %d %d %d %d %d ",
b->bits.b0,
b->bits.b1,
b->bits.b2,
b->bits.b3,
b->bits.b4,
b->bits.b5,
b->bits.b6,
b->bits.b7
);
}
void printInt(int_t *i)
{
printf("%p: ", i);
printByte(&i->bytes.b0);
printByte(&i->bytes.b1);
printByte(&i->bytes.b2);
printByte(&i->bytes.b3);
putchar('\n');
}
int main()
{
int_t i1, i2;
i1.value = 0x00000001;
i2.value = 0x80000000;
printInt(&i1);
printInt(&i2);
return 0;
}
Possible output:
0x7ffea0e30920: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0x7ffea0e30924: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
Additional (based on the comment of #chqrlie):
I've previously used the unsigned char type, but the C Standard allows only 3 - and since C99 - 4 types. Additional implementation-defined types may be acceptable by the C Standard and it seems that gcc was ok with the unsigned char type for the bit field, but i've changed it nevertheless to the allowed type _Bool (since C99).
Noteworthy: The order of bit fields within an allocation unit (on some platforms, bit fields are packed left-to-right, on others right-to-left) are undefined (see Notes section in the reference).
Reference to bit fields: https://en.cppreference.com/w/c/language/bit_field
p = (long long)p + 1; is bad code (undefined behavior UB (e.g. bus fault and re-booted machine)) as it is not specified to work in C. The attempted assigned of the newly formed address is not certainly aligned to int * needs.
Don`t do that.
To look at the bytes of a[]
#include <stdio.h>
#include <stdlib.h>
void dump(size_t sz, const void *ptr) {
const unsigned char *byte_ptr = (const unsigned char *) ptr;
for (size_t i = 0; i < sz; i++) {
printf("%p %02X\n", (void*) byte_ptr, *byte_ptr);
byte_ptr++;
}
}
int main(void) {
unsigned int a[3] = {1, 1, 0x7f7f0501u};
dump(sizeof a, a);
}
As this is wiki, feel open to edit.
There are multiple instances of undefined behavior in your code:
in printf("%d %p\n", *p, p) you should cast p as (void *)p to ensure printf receives a void * as it expects. This is unlikely to pose a problem on most current targets but some ancien systems had different representations for int * and void *, such as early Cray systems.
in p = (long long)p + 1, you have implementation defined behavior converting a pointer to an integer and implicitly converting the integral result of the addition back to a pointer. More importantly, this may create a pointer with incorrect alignment for accessing int in memory, resulting in undefined behavior when you dereference p. This would cause a bus error on many systems, eg: most RISC architectures, but by chance not on intel processors. It would be safer to compute the pointer as p = (void *)((intptr_t)p + 1); or p = (void *)((char *)p + 1); albeit this would still have undefined behavior because of alignment issues.
is the number 1 stored in memory as 00000001 00000000 00000000 00000000?
Yes, your system seems to use little endian representation for int types. The least significant 8 bits are stored in the byte at the address of a, then the next least significant 8 bits, and so on. As can be seen in the output, 1 is stored as 01 00 00 00 and 0x7f7f0501 stored as 01 05 7f 7f.
Why is 16777216 printed in the output?
The second instance of printf("%d %p\n", *p, p) as undefined behavior. On your system, p points to the second byte of the array a and *p reads 4 bytes from this address, namely 00 00 00 01 (the last 3 bytes of 1 and the first byte of the next array element, also 1), which is the representation of the int value 16777216.
To dump the contents of the array as bytes, you should access it using a char * as you do in the last loop. Be aware that char may be signed on some systems, causing for example printf("%x\n", *p3); to output ffffff80 if p3 points to the byte with hex value 80. Using unsigned char * is recommended for consistent and portable behavior.
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
I'm getting a lot of extra bytes when I find the twos complement of a byte.
for example "eb" turns into "ffffff15". When I printf this, it's -235, not -21 like I would expect it to be.
//unsigned char a[] holds bytes
int b=(int)a[i];
bit1=(b & 0x80 ? 1 : 0);
if (bit1==1){
b=((~b)+1);
}
printf("b: %02x",b);
this prints ffffff15. (%d prints -235).
You did not post the complete code, but it appears a must be an unsigned char array or a unsigned char pointer, or a char array and the type char is unsigned on your platform. Casting a[i] as (int) does not change the value, and evaluates to 235.
The formula b=((~b)+1); does not extend the most significant bit, but merely computes as b = -b. Hence the result -235.
To replicate to most significant bit, you could write:
b = (a[i] & 0xFF) | (-bit1 & ~0xFF);
Here is a complete example:
#include <stdio.h>
int main() {
// a is a byte array
unsigned char a[] = "0a\xeb";
for (size_t i = 0; i < sizeof a; i++) {
int b = (int)a[i];
int s = (b & 0xFF) | ((b & 0x80) ? ~0xFF : 0);
printf("a[%zd] = 0x%hhx, b: 0x%x, %d, s: 0x%x, %d\n",
i, a[i], b, b, s, s);
}
return 0;
}
It prints:
a[0] = 0x30, b: 0x30, 48, s: 0x30, 48
a[1] = 0x61, b: 0x61, 97, s: 0x61, 97
a[2] = 0xeb, b: 0xeb, 235, s: 0xffffffeb, -21
a[3] = 0x0, b: 0x0, 0, s: 0x0, 0
Trying to understand the problem: "eb turns into ffffff15. When I printf this, it's -235, not -21".
So it seems that you expect ffffff15 to represent -21 in decimal, and this seems as if you had a (very common) misunderstanding in how negative integral values are represented: Making a number negative does not just set a single "negative" bit, but actually inverts all the bits (and adds 1). Let's assume an 8 bit example:
1..0000001 -1..11111111
2..0000010 -2..11111110
3..0000011 -3..11111101
...
As you can see, making an integral number int x negative turns it actually into INT_MAX - x + 1 (which is the same as ~x + 1), not into x | 0x800000. In the other way round, 0xfffff15 represents 0xfffffff - 0xeb + 1, which means -235, not -21.
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
I want to convert two ASCII bytes to one hexadecimal byte.
eg.
0x30 0x43 => 0x0C , 0x34 0x46 => 0x4F ...
The ASCII bytes are a number between 0 and 9 or a letter between A and F (upper case only), so between 0x30 ... 0x39 and 0x41 ... 0x46
I know how "to construct" 0x4F with the numbers 0x34 and 0x46 : 0x4F = 0x34 * 0x10 + 0x46
So, in fact, i would to convert one ASCII byte in hexadecimal value.
For that, i can build and array to assign the hexadecimal value to the ASCII char :
0x30 => 0x00
0x31 => 0x01
...
0x46 => 0x0F
But, maybe it have a most « proper » solution.
The program will be run on an AVR µC and is compiled with avr-gcc, so scanf() / printf() solutions aren't suitable.
Have you got an idea ?
Thanks
i can't make sense of your examples, but if you want to convert a string containing hexadecimal ascii characters to its byte value (e.g. so the string "56" becomes the byte 0x56, you can use this (which assumes your system is using ASCII)
uint8_t*
hex_decode(const char *in, size_t len,uint8_t *out)
{
unsigned int i, t, hn, ln;
for (t = 0,i = 0; i < len; i+=2,++t) {
hn = in[i] > '9' ? in[i] - 'A' + 10 : in[i] - '0';
ln = in[i+1] > '9' ? in[i+1] - 'A' + 10 : in[i+1] - '0';
out[t] = (hn << 4 ) | ln;
}
return out;
}
You'd use it like e.g.
char x[]="1234";
uint8_t res[2];
hex_decode(x,strlen(x),res);
And res (which must be at least half the length of the in parameter) now contains the 2 bytes 0x12,0x34
Note also that this code needs the hexadecimal letters A-F to be capital, a-f won't do (and it doesn't do any error checking - so you'll have to pass it valid stuff).
You can use strtol(), which is part of avr-libc, or you can write just your specific case pretty easily:
unsigned char charToHexDigit(char c)
{
if (c >= 'A')
return c - 'A' + 10;
else
return c - '0';
}
unsigned char stringToByte(char c[2])
{
return charToHexDigit(c[0]) * 16 + charToHexDigit(c[1]);
}
The task:
Convert a string containing hexadecimal ascii characters to its byte values
so ascii "FF" becomes 0xFF and ascii "10" (x31x30x00) becomes 0x10
char asciiString[]="aaAA12fF";// input ascii hex string
char result[4]; // byte equivalent of the asciiString (the size should be at half of asciiString[])
// the final result should be:
result[0] = 0xAA;
result[1] = 0xAA;
result[2] = 0x12;
result[3] = 0xFF;
//1. Firt step: convert asciiString so it contains upper cases only:
// convert string to upper cases:
stringToUpperCases(asciiString);
use:
void stringToUpperCases(char *p)
{
for(int i=0; *(p+i) !='\0'; i++)
{
*(p+i) = (unsigned char) toupper( *(p+i) );
}
}
//2. Convert a string containing hexadecimal ascii characters to its byte values:
// convert string to bytes:
int nrOfBytes = stringToBytes(asciiString,result);
//use:
unsigned char charToHexDigit(char c)
{
if (c >= 'A')
return (c - 'A' + 10);
else
return (c - '0');
}
unsigned char ascii2HexToByte(char *ptr)
{
return charToHexDigit( *ptr )*16 + charToHexDigit( *(ptr+1) );
}
int stringToBytes(char *string, char *result)
{
int k=0;
int strLen = strlen(string);
for(int i = 0; i < strLen; i = i + 2)
{
result[k] = ascii2HexToByte( &string[i] );
k++;
}
return k; // number of bytes in the result array
}
//3. print result:
printNrOfBytes(nrOfBytes, result);
// use:
void printNrOfBytes(int nr, char *p)
{
for(int i= 0; i < nr; i++)
{
printf( "0x%02X ", (unsigned char)*(p+i) );
}
printf( "\n");
}
//4. The result should be:
0xAA 0xAA 0x12 0xFF
//5. This is the test program:
char asciiString[]="aaAA12fF"; // input ascii hex string
char result[4]; // result
// convert string to upper cases:
stringToUpperCases(asciiString);
// convert string to bytes
int nrOfBytes = stringToBytes(asciiString,result);
// print result:
printNrOfBytes(nrOfBytes, result);
// result:
// 0xAA 0xAA 0x12 0xFF
It's works, but could be much optimized !
inline uint8_t twoAsciiByteToByte(const std::string& s)
{
uint8_t r = 0;
if (s.length() == 4)
{
uint8_t a = asciiToByte(s[0]);
uint8_t b = asciiToByte(s[1]);
uint8_t c = asciiToByte(s[2]);
uint8_t d = asciiToByte(s[3]);
int h = (a * 10 + b);
int l = (c * 10 + d);
if (s[0] == '3')
h -= 30;
else if (s[0] == '4')
h -= 31;
if (s[2] == '3')
l -= 30;
else if (s[2] == '4')
l -= 31;
r = (h << 4) | l;
}
return r;
}
Here's a version that works with both upper and lower-case hex strings:
void hex_decode(const char *in, size_t len, uint8_t *out)
{
unsigned int i, hn, ln;
char hc, lc;
memset(out, 0, len);
for (i = 0; i < 2*len; i += 2) {
hc = in[i];
if ('a' <= hc && hc <= 'f') hc = toupper(hc);
lc = in[i+1];
if ('a' <= lc && lc <= 'f') lc = toupper(lc);
hn = hc > '9' ? hc - 'A' + 10 : hc - '0';
ln = lc > '9' ? lc - 'A' + 10 : lc - '0';
out[i >> 1] = (hn << 4 ) | ln;
}
}
Converting 2 hex chars to a byte is done in two steps:
Convert char a and b to their number (e.g. 'F' -> 0xF), which is done in two big if else branches, that check if the char is in the range '0' to '9', 'A' to 'F' or 'a' to 'f'.
In the 2nd step the two numbers are joined by shifting a (largest value is 0xF (0b0000_FFFF)) 4 to the left (a << 4 -> 0b1111_0000) and then apply the bitwise or operation on a and b ((a << 4) | b):
a: 0000_1111
b: 1111_0000
-> 1111_1111
#include <stdio.h>
#include <stdint.h>
#define u8 uint8_t
#define u32 uint32_t
u8 to_hex_digit(char a, char b) {
u8 result = 0;
if (a >= 0x30 && a <= 0x39) {
result = (a - 0x30) << 4;
} else if (a >= 0x41 && a <= 0x46) {
result = (a - 0x41 + 10) << 4;
} else if (a >= 0x61 && a <= 0x7A) {
result = (a - 0x61 + 10) << 4;
} else {
printf("invalid hex digit: '%c'\n", a);
}
if (b >= 0x30 && b <= 0x39) {
result |= b - 0x30;
} else if (b >= 0x41 && b <= 0x46) {
result |= b - 0x41 + 10;
} else if (b >= 0x61 && b <= 0x7A) {
result |= b - 0x61 + 10;
} else {
printf("invalid hex digit: '%c'\n", b);
}
return result;
}
u32 main() {
u8 result = to_hex_digit('F', 'F');
printf("0x%X (%d)\n", result, result);
return 0;
}