I wrote a program to output numbers in bytes and addresses of storage of these bytes, but the teacher says that the addresses of the fields are stored in complex data types are not stored sequentially, but my version of the program is not true. Actually the question is how to get the address of the structure field? Code attached:

#include <iostream> #include <stdlib.h> #include <stdio.h> #include <locale.h> using namespace std; typedef unsigned char *byte_ptr; void print_int(byte_ptr start, int size) { cout << "Вывод числа типа int "; for (int i = 0; i < size; i++) printf("\n|%p|%2x|", &start[i], start[i]); } void print_float(byte_ptr start, int size) { cout << "Вывод числа типа float "; for (int i = 0; i < size; i++) printf("\n|%p|%2x|", &start[i], start[i]); } void print_double(byte_ptr start, int size) { cout << "Вывод числа типа double "; for (int i = 0; i < size; i++) printf("\n|%p|%2x|", &start[i], start[i]); } int main() { setlocale(0, ""); struct Numbers { int x; float y; double z; } Byte; Byte.x = 15; Byte.y = 15; Byte.z = 15; print_int((byte_ptr) &Byte.x, sizeof(Byte.x)); cout << endl; print_float((byte_ptr) &Byte.y, sizeof(Byte.y)); cout << endl; print_double((byte_ptr) &Byte.z, sizeof(Byte.z)); cout << endl; system("PAUSE"); return 0; } 

How it looks on the console enter image description here

  • Nothing is clear. Why are three identical functions written? Why is there a difference in the first one (find yourself)? What does the correctness of a program have to do with how data is stored in structures? - AnT
  • The teacher says that in complex data types field alignment is used, so the structure fields (namely, the fields) may not be located in consecutive addresses. The question is, how does this all clearly show on the console? - vosure
  • Swap float and double in the structure. - AnT
  • Why, nothing will change? I checked - vosure
  • Why not change? In the default alignment settings for your address listing, it will be clearly visible that after the first field an unused "hole" of 4 bytes was formed. - AnT

2 answers 2

How to get the address of the structure field?

So you do it right:

 (byte_ptr)&Byte.x 

True, casting pointers to another type is not a good idea, but that is another question.

Further, in the print_... functions you try to break this number into bytes and output them in order with the address, but for some reason in the first case you forgot the address taking operator:

 printf("\n|%p|%2x|", &start[i], start[i]); 

Data is stored in structures sequentially, but empty spaces may appear between them. For example, if you have a 32-bit architecture, and the first field of the structure is of type char, and the second is float, then 3 empty bytes will appear between them. This is called alignment.

And, yes, AnT rightly noticed that your three functions are exactly the same. If you are in a function that prints a float, pass the address to a double, then it prints it correctly.


UPD. To see the empty spaces between the fields of the structure, you need to arrange these fields so that this space is required. Here it is well described, when and why these spaces appear, and how to avoid them.

In your case, most likely, you can just double in the middle. Or add char to the beginning.

  • And how to bring this alignment to the screen? I attached a screen of how it looks now - vosure
  • one
    @vosure, for example, like this: size_t filled_by = (char *)&Byte.z - (char *)&Byte.x - sizeof(Byte.x) . - PinkTux
  • @vosure: on Linux, you can see how the struct in memory looks like using the pahole utility ( sudo apt install dwarves ). In your case, you can take out the struct Numbers from main() so that it becomes visible and compile with debug info ( -g ). Then the gcc -g *.c && pahole a.out will show the location of the elements in the structure. - jfs

If you use the capabilities of the preprocessor, you can describe all the fields in one array of structures and print everything in detail (together with the spaces between the fields).

 #include <stdio.h> int main() { struct { int x; double z; float y; } bytes = {1, 1, 0}; struct { void *addr; size_t len; const char *type, *name; } info[] = { #define FIELD(f,T) {&(f), sizeof(f), #T, #f} FIELD(bytes.x, int), FIELD(bytes.z, double), FIELD(bytes.y, float), #undef FIELD {&bytes + 1, 0}}; unsigned char *b = (unsigned char *)&bytes, *eb = (unsigned char *)(&bytes + 1); printf("struct bytes (%p:%p %zu bytes) content:\n", b, eb, sizeof(bytes)); for (size_t i = 0; info[i].len; i++) { printf("%p:%p %2zu %s %s\t: " , info[i].addr, (char *)info[i].addr + info[i].len, info[i].len, info[i].type, info[i].name); for (eb = b + info[i].len; b < eb; b++) printf("%02x ", *b); for (; (void *)b != info[i + 1].addr; b++) printf(".. "); puts(""); } } 

It turns out something like this (in 64-bit Linux)

 avp@avp-ubu1:hashcode$ g++ tt.cpp -Wall -O3 -std=c++17 avp@avp-ubu1:hashcode$ ./a.out struct bytes (0x7ffc4bf91040:0x7ffc4bf91058 24 bytes) content: 0x7ffc4bf91040:0x7ffc4bf91044 4 int bytes.x : 01 00 00 00 .. .. .. .. 0x7ffc4bf91048:0x7ffc4bf91050 8 double bytes.z : 00 00 00 00 00 00 f0 3f 0x7ffc4bf91050:0x7ffc4bf91054 4 float bytes.y : 00 00 00 00 .. .. .. .. avp@avp-ubu1:hashcode$ 

The last element of the array of structure field descriptors must be initialized with the address following the structure and zero length.

  • Sorry, that offtopic :) It would be interesting to have an opinion on this issue , a branch about jmalloc and so on. (oh, I slept) - PinkTux
  • @PinkTux, let's have it tomorrow, I was going to sleep ... - avp
  • OK, this is not in a hurry. - PinkTux
  • @PinkTux, I read. Are you interested in the opinion about jemalloc.net/jemalloc.3.html ? (or is it in the context of restricted and volatile?) It seems powerful, but a specific task is needed for the stimulus to study it thoroughly. And benchmarks for comparison with the standard lnuksovoy done? - avp
  • Until I picked it in detail. First of all, he is interested not in an allocator, but as a means of catching errors that valgrind allegedly cannot cope with. As for the stimulus, I agree. - PinkTux