Memory allocation of a structure / value of a structure - c

Can you help me to understand why the value of my dataStruct structure isn't the value of one of its members? (As for the simpleDataStruct strucure)
I print the value with this line:
printf("dataStruct:..............0x%X\r\n", dataStruct);
And the result is:
dataStruct:..............0x22FE20
I use GCC.
My code is:
int main(void)
{
typedef struct Main_SimpleStructData_s
{
unsigned char a;
unsigned char b;
}
Main_SimpleStructData_t;
typedef struct Main_StructuredData_s
{
unsigned char a;
unsigned char* b;
}
Main_StructuredData_t;
unsigned char localDataA = 0xBE;
unsigned char localDataB = 0xEF;
unsigned char localDataC = 0xCA;
unsigned char localDataD = 0xFE;
Main_SimpleStructData_t simpleDataStruct;
Main_StructuredData_t dataStruct;
simpleDataStruct.a = localDataA;
simpleDataStruct.b = localDataB;
dataStruct.a = localDataC;
dataStruct.b = &localDataD;
printf("\r\n");
printf("simpleDataStruct:........0x%X\r\n", simpleDataStruct);
printf("Addr simpleDataStruct: 0x%X\r\n", &simpleDataStruct);
printf("Size simpleDataStruct: %u\r\n", (unsigned)sizeof(simpleDataStruct));
printf("\r\n");
printf("Addr localDataC: 0x%X\r\n", &localDataC);
printf("Size localDataC: %u\r\n", (unsigned)sizeof(localDataC));
printf("Addr localDataD: 0x%X\r\n", &localDataD);
printf("Size localDataD: %u\r\n", (unsigned)sizeof(localDataD));
printf("dataStruct:..............0x%X\r\n", dataStruct);
printf("dataStruct.a: 0x%X\r\n", dataStruct.a);
printf("dataStruct.b: 0x%X\r\n", dataStruct.b);
printf("Addr dataStruct: 0x%X\r\n", &dataStruct);
printf("Addr dataStruct.a: 0x%X\r\n", &(dataStruct.a));
printf("Addr dataStruct.b: 0x%X\r\n", &(dataStruct.b));
printf("Size dataStruct: %u\r\n", (unsigned)sizeof(dataStruct));
return (0);
}
And the result is:
simpleDataStruct:........0xEFBE
Addr simpleDataStruct: 0x22FE4A
Size simpleDataStruct: 2
Addr localDataC: 0x22FE4D
Size localDataC: 1
Addr localDataD: 0x22FE4C
Size localDataD: 1
dataStruct:..............0x22FE20
dataStruct.a: 0xCA
dataStruct.b: 0x22FE4C
Addr dataStruct: 0x22FE30
Addr dataStruct.a: 0x22FE30
Addr dataStruct.b: 0x22FE38
Size dataStruct: 16
In advance, thank you.

The %X conversion takes an unsigned int argument. You incorrectly pass a struct Main_StructuredData_s, which is not an unsigned int, which is undefined behaviour, so I don't know why you would expect to see something reasonable as the result.
edit: As for why the Main_SimpleStructData_t appears to "work" by showing its members, the answer is still that it's undefined behaviour and it may do whatever, including the "correct" thing. The underlying reason in this particular case is almost certainly:
printf tries to read an unsigned int argument (because it doesn't know what you actually passed, when you say that you passed an unsigned int)
The small Main_SimpleStructData_t happens to be passed as an argument in the same way as an unsigned int would be (on your platform), and the printf ends up reading in its members' values.
The larger Main_StructuredData_t happens to be passed as an argument in a different way (e.g., on the stack instead of in a register) and the printf reads some random value instead because the struct isn't in the place where the unsigned int argument would have been.

When you call the function printf, the arguments are pushed on the stack.
printf pops the stack when printing out the values from the stack. the stack contains no information about the data type, that is the job for the format specifier.
The format specifier tells printf about the datatypes passed on the stack and then knows the sizes of those arguments, it has otherwise no way of knowing.
printf cannot handle a user-defined struct like that if you give the format specifier %x will just try something but it is undefined behavior. You can write out the address of the struct prefix it with & and or the members of the struct, but not the struct itself.
You can write your own printf function with a custom format specifier that internally prints out the members after passing the struct by value, but as it is now you have not. search for stdarg.h for more info

#EOF, #Ctx, #Anders and #Arkku: Thank you very much for your help. I understand that the problem is between the laptop and my chair ;) I was stupid but now I'm a man :)
To summary, I don't know use correctly the printf function. GCC had been advertised me with the warnings but I didn't read those...
If my simple Main_SimpleStructData_t structure becomes more complicated, the behaviour is the same: Undefined !
typedef struct Main_SimpleStructData_s
{
unsigned char a;
unsigned int c; // Add a little bit complication
unsigned char b;
}
Main_SimpleStructData_t;
The result becomes:
simpleDataStruct:......0x22FE20 // Undefined behaviour also !
Addr simpleDataStruct: 0x22FE40
Size simpleDataStruct: 12

Related

how to convert int to void *?

I'm trying to make an analogue of sscanf with a specifier %p.
I use this:
int res = ahex2num(buf);
*va_arg(ap, void **) = (void *) res;
It works correctly, i actually get the address i pass, like 0x1A but i am facing this error:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
In main function:
int main(){
void *a;
readFromStr("0x1A", "%p", &a);
printf("%p", a);
return 0;
}
/*
out: 0x1a
*/
Can I somehow avoid this?
long ahex2num(unsigned char *in){
unsigned char *pin = in;
long out = 0;
while(*pin != 0){
out <<= 4;
out += (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9;
pin++;
}
return out;
}
Apparently pointers, particularly void *, have a different size than int on your system. E.g., pointers may be 64 bits and int may be 32 bits. Implementing %p in a routine like sscanf is a valid reason for converting an integer to void *, but you need to use an integer type that can hold all the bits needed for a pointer. A good type for this may be uintptr_t, declared in <stdint.h>.
You will need to ensure all the code that works with the integers from the scanning, such as ahex2num, can support the necessary width and signedness, including handling potential overflow as desired.
If I had your entire code, I could test it. I assume to remove the warning without using a pragma is as simple as changing your typecast from int to long int.
I solved this problem like this:
long long int res = ahex2num(buf);

Print/store n bytes of u_char pointer in c?

I am trying to make a function to print/store the first n bytes of an u_char pointer. This is what I currently have (just trying to print the first value), but it doesn't work.
void print_first_value(const u_char * p) {
printf("%d", p[0]);
}
I have also tried this:
void print_first_value(const u_char * p) {
printf("%d", &p[0]);
}
How would I make this work? In the end I want to loop through the individual values in *p, but I can only print the entire string at the address pointed to by p via this code.
void print_first_value(const u_char * p) {
printf("%s", p);
}
So what I am printing out is packets, sorry I didn't mention that. The last snippet of code prints a packet in hex, so something like 0050 5686 7654 0000... and I want to print/store the values at certain indexes. So I want the first two blocks 00505686, then the next two and so on.
First of all, a few notes about your code:
u_char isn't a standard type. unsigned char is the standard way of spelling this type. While you might be using a typedef in your codebase (such as typedef unsigned char u_char;), it's a better idea to use the standard type, particularly when posting code using that typedef without the typedef itself.
&p[0] and p mean the exact same thing in C, regardless of the value of p (assuming that it is a pointer). By the same reasoning, p[0] and *p also mean the same thing. I'll be using p and *p exclusively in further examples, but keep in mind the equivalence.
unsigned char is an integral type. This means that its value is an integer. The fact that this value can also be interpreted as a character is incidental. This will be very relevant soon.
Now, as for your snippets. Let's go in reverse order. The last one just prints the string, as you know.
The second one is undefined behavior. printf("%d", p) (&p[0] = p, remember?) is passing a pointer as an argument (p is of type const unsigned char *), but %d expects an int. The arguments must match the types indicated by the format specifiers; it is an error to do otherwise. It will probably "work" (as in, not crash), but it's something you definitely shouldn't do. It's not valid C.
The first one is the most interesting one. First of all, printf("%d", *p) isn't undefined behavior, unlike the second snippet's case. *p is const unsigned char (the pointer has been dereferenced), and any type narrower than int gets promoted to int on variadic parameter lists (printf is defined as int printf(const char *, ...); the , ... at the end indicates that it accepts any number of arguments of any type, and it is often referred to as variadic because of this reason), so this is valid.
And in fact, it works. Let's try a full program using it:
#include <stdio.h>
void print_first_value (const unsigned char * p) {
printf("%d", *p);
}
int main (void) {
char str[] = "Hello world!";
print_first_value(str);
return 0;
}
Assuming you're not using a particularly strange computer or OS, you'll get 72 printed this way. This is not wrong! 72 happens to be the number (called a codepoint) that internally represents a capital letter H in ASCII. Remember how I said that unsigned char was an integral type? This is what it means: its value is really a number. You asked your computer to print the number, and it did.
If you want to print the character that this number represents, though, you have two choices: use %c as a format specifier in printf (which tells it to print the character) or use the putchar/putc functions (which take a single number and print the character they represent). Let's go with the latter:
#include <stdio.h>
void print_first_character (const char * p) {
// it doesn't matter if it is unsigned or signed,
// because we're just printing the character
putchar(*p);
}
int main (void) {
char str[] = "Hello world!";
print_first_character(str);
return 0;
}
Now you'll get H. Getting somewhere! Now, to print all the characters in the string, we need to know one extra detail: after all meaningful characters in a string, the very last one is always zero. As in, the number zero, not the character '0'. (This is often written as '\0', but that is the same as zero.) So, here we go:
#include <stdio.h>
void print_first_character (const char * p) {
putchar(*p);
}
int main (void) {
char message[] = "Hello world!";
const char * str = message; // initialize the pointer to the beginning of the string
while (*str) { // while *str isn't zero
print_first_character(str); // print the character...
str ++; // ...and advance to the next one
}
putchar('\n'); // let's print a newline too, so the output looks nicer
return 0;
}
And here we go! Hello world! will be printed. Of course, puts("Hello world!"); would have done the same, but that isn't as fun, now is it?
Per Your Edit You Are Printing Packets
Ah hah! That makes more sense. When you create an unsigned char pointer to an unsigned value you have a pointer to the beginning of the value in memory, but how the value is stored will depend on endianness of the machine and the byte-order of the bytes in the packet.
Simply storing/printing out the bytes as they are currently stored in memory isn't difficult, nor is storing/printing each two-bytes. Each may be done with something similar to:
/* all bytes stored in memory */
void prn_all (const unsigned char *p, size_t nbytes)
{
while (nbytes--)
printf ("0x%02x\n", p[nbytes]);
}
/* each 2-bytes stored in memory */
void prn_two (const unsigned char *p, size_t nbytes)
{
while (nbytes--) {
printf ("%02x", p[nbytes]);
if (nbytes % 2 == 0)
putchar ('\n');
}
}
...
unsigned u = 0xdeadbeef;
unsigned char *p = (unsigned char *)&u;
prn_all (p, sizeof u);
putchar ('\n');
prn_two (p, sizeof u);
Would result in:
$ /bin/prn_uchar_byte
0xde
0xad
0xbe
0xef
dead
beef
Now the caveat. Since you mention "packet", depending on whether the packet is in network-byte-order or host-byte-order, you may need a conversion (or simple bit shifts) to get the bytes in the order you need. C provides functions to convert between network-byte-order and host-byte-order and vice-versa with man 3 byteorder htonl, htons, ntohl, ntohs. Needed because network byte order is Big Endian while normal x86 and x86_64 is Little Endian. If your packages are in network byte order and you need host byte order, you can simply call ntohs (network to host short) to convert each two-byte value to host order, e.g.
/* each 2-bytes converted to host byte order from network byte order */
void prn_two_host_order (const unsigned char *p, size_t nbytes)
{
for (size_t i = 0; i < nbytes; i+=2) {
uint16_t hostorder = ntohs (*(uint16_t*)(p+i));
printf ("%04" PRIx16 "\n", hostorder);
}
}
...
prn_two_host_order (p, sizeof u);
Results in:
efbe
adde
(note: the prototype for ntohs (and all byteorder conversions) use exact-width types uint16_t and uint32_t -- for which the associated print macros are in inttypes.h -- which also automatically includes stdint.h)
You will have determine the order you have in your "packets" to know whether a byteorder conversion is needed. That will depend on how you get your data.
Putting it altogether in a short example, you could do something like:
#include <stdio.h>
#include <inttypes.h>
#include <arpa/inet.h>
/* all bytes stored in memory */
void prn_all (const unsigned char *p, size_t nbytes)
{
while (nbytes--)
printf ("0x%02x\n", p[nbytes]);
}
/* each 2-bytes stored in memory */
void prn_two (const unsigned char *p, size_t nbytes)
{
while (nbytes--) {
printf ("%02x", p[nbytes]);
if (nbytes % 2 == 0)
putchar ('\n');
}
}
/* each 2-bytes converted to host byte order from network byte order */
void prn_two_host_order (const unsigned char *p, size_t nbytes)
{
for (size_t i = 0; i < nbytes; i+=2) {
uint16_t hostorder = ntohs (*(uint16_t*)(p+i));
printf ("%04" PRIx16 "\n", hostorder);
}
}
int main (void) {
unsigned u = 0xdeadbeef;
unsigned char *p = (unsigned char *)&u;
prn_all (p, sizeof u);
putchar ('\n');
prn_two (p, sizeof u);
putchar ('\n');
prn_two_host_order (p, sizeof u);
}
(note: some systems use the header netinet/in.h instead of arpa/inet.h for the byteorder conversion as listed in the man page)
Full Example Use/Output
$ /bin/prn_uchar_byte
0xde
0xad
0xbe
0xef
dead
beef
efbe
adde
You can store the values instead of printing -- but that is left to you. Look things over and let me know if you have questions.

Can we print the data just by using bare address in C?

I was wondering whether we can print data at a particular location just by using the bare address of that location in C language.
for eg, Here is the code I used :
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *(0x7fff47808f50));
return 0;
}
But it is showing error. Maybe I've used the wrong syntax or maybe this is not the way to do it.Anyhow, please tell me the right way to do it.
You could (thought shouldn't) cast the integer to a pointer like so: (void *) 0x7fff47808f50.
The conversion has implementation-defined and undefined aspects, however, meaning your mileage will vary. The value will obviously change from compiler to compiler, perhaps even for different compilations, and byte order probably won't be the same as the way we conventionally write numbers, meaning you'll probably have to tinker quite a bit to get this working.
This is nonetheless demonstrable in practice, when that implementation-defined behaviour allows us to reproduce that behaviour, the following will be compliant:
unsigned long long ptr_as_integer = (unsigned long long) "hello world";
printf("%s", (void *) ptr_as_integer);
int value = 42;
unsigned long long value_ptr_as_integer = (unsigned long long) &value;
printf("%d", * (int *) value_ptr_as_integer);
There's also the uintptr_t type, which is designed specifically for this, but that's optional and so not guaranteed to exist...
It's fine to be curious; that's how we learn best... but please don't use this in practice! How often have you been taught not to use magic numbers?
You can use a char * to alias a pointer of another type to read individual bytes:
int i;
char *p = (char *)ptr;
for (i=0; i<sizeof(*ptr); i++) {
printf("p[%d]=%02hhx", i, p[i]);
}
Modify your code
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *ptr);
return 0;
}
the answer to you question is YES.
BUT:
You must be 100% sure what address to use. For example in any kind of firmware you always have addresses of registers defined in manuals as regular numbers. and we use them like this
#define MY_REG_ADDR 0x12345ABC
int a = *((int*)(MY_REG_ADDR))
Modern OSes do address randomization so executable's virtual address sapce is changed every time you run your application so you CANNOT just use hardcoded address.
here is the output after i ran the app 4 times (modified code)
Address: 0x7ffc279af5ac
Data: 10
Address: 0x7ffc2d78021c
Data: 10
Address: 0x7fffb36ae32c
Data: 10
Address: 0x7ffca2c2a9ec
Data: 10
Every tine you change your code memory layout might change so variabl's address might also change

code snippet warning: cast to pointer from integer of different size

In the code snippet below, i get this warning - "warning: cast to pointer from integer of different size" in line number 25
which is the 3rd printf i do,
printf("value of a thru struct ptr=%d\n",(unsigned char *)m_arr(ptr_ns_type)[0]);
I dont understand this warning since i do the same thing (except not using macros) in the 2nd printf
printf("value of a thru ptr=%d\n",(unsigned char)*ptr);
for which i dont get any error. could anyone help me in understanding this warning please?
Thanks,
Badri.
#include<stdio.h>
struct ns
{
int i;
unsigned char a[2];
};
#define m_arr(whatever) ((struct ns *)whatever)->a
int main()
{
unsigned char arr[2];
unsigned char brr[2];
struct ns ns_type;
struct ns *ptr_ns_type;
arr[0]=192;
arr[1]=168;
brr[0]=172;
brr[1]=188;
ns_type.i=5;
ns_type.a[0]=brr[0];
ptr_ns_type = &ns_type;
unsigned char *ptr=arr;
printf("value of a=%d\n",arr[0]);
printf("value of a thru ptr=%d\n",(unsigned char)*ptr);
printf("value of a thru struct ptr=%d\n",(unsigned char *)m_arr(ptr_ns_type)[0]);
return 0;
}
You don't need a cast here:
printf("value of a thru ptr=%d\n",(unsigned char)*ptr);
because ptr is a pointer to unsigned char, so *ptr is already an unsigned char.
However, here:
(unsigned char *)m_arr(ptr_ns_type)[0]
which translates to:
(unsigned char *)((struct ns *)ptr_ns_type)->a[0]
you are trying to cast unsigned char to a pointer to an unsigned char. I think what you want is:
((struct ns *)ptr_ns_type)->a[0]
but also note that the (struct ns *) cast is not necessary.
Actually, you aren't doing the same thing at all. Try getting rid of the macro, by doing the text substitution by hand. For example, lets create a variable tmp that is of type unsigned char*:
unsigned char* tmp1 = (unsigned char *) ((struct ns *)ptr_ns_type)->a[0];
You will get the same warning. So the macro has nothing to do with it. Further, the casting is to struct ns * is superfluous and evil since it removes valuable type checking. So we can get rid of it to get clearer code:
unsigned char* tmp1 = (unsigned char *) ptr_ns_type->a[0];
Of course, you still get the completely correct warning, but hopefulll it is now clear what is going on. When you call ptr_ns_type->a[0], you are dereferencing ptr_ns_type to obtain the array a, and using the [] operator to get the value of a[0], which is an unsigned char, and not a pointer to an unsigned char.
If you want to obtain the address of a[0], you can do so by leaving out the [0] operation:
unsigned char* tmp1 = (unsigned char *) ptr_ns_type->a;
I assume this is an exercise to help you undertand the fine points of pointers, arrays, macros and casts. Please learn the following lessons:
1. Macros are evil. Only use them when they increade the clarity of your code.
2. Avoid unecessary casting. It's unsafe.
3. Simplify, simplify. Once we simplified the code in question, the error became immediately obvious.

Write own printf function, trying to include %p.

So I'm writing my own printf function so I'm using stdarg.h and the system call write(). But I have no idea on how to incorrect %p into my function. Would %X produce the same result?
I have %x done as so:
'x': x=va_arg(argp,argp, unsigned int);
char *temp = convert(x,16);
write(1, temp, lengthOFtemp);
break;
char *convert(unsigned int, int)
{
static char buf[33];
char *ptr;
ptr=&buf[sizeof(buff)-1];
*ptr='\0';
do
{
*--ptr="0123456789abcdef"[num%base];
num/=base;
}while(num!=0);
return(ptr);
}
The difference between %p and %X is that pointer sizes are platform specific - 8 bytes on 64-bit platforms, 4 bytes on 32-bit platforms. Thus, you must use an 'unsigned long' variable to handle the pointer argument from va_args, not 'unsigned int' which remains 4 bytes on some 64-bit platforms.
Otherwise yes, very much like the %X code you have above.
You might like to use
void * pv = va_arg(va, void*)
to pull the pointer from the variadic argument list.
To safely receive pointers this way the caller of the variadic function, which does the pulling as shown above, needs to pass in pointers as being casted to void *.
Then do the conversion to integer like so:
#include <inttypes.h>
...
uintptr_t uipv = (uintptr_t) pv;
and finally call a conversion function:
char buff[64] = {0};
char * pc = convert_uintptr(uipv, 16);
with:
char * convert_uintptr(uintptr_t uipv, unsigned base);

Resources