Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the value of a pointer-to-member always the same for different members of the same struct?

I have the following code:

#include <iostream>
#include <string>

using namespace std;

struct foo_s {
    string a;
    string b;
    string c;
};

void print_field(foo_s* foo, string foo_s::* field) {
    cout << "field: " << field << " - " << foo->*field << endl;
}

int main() {
   foo_s my_foo = {
       "a",
       "b",
       "c",
   };

   print_field(&my_foo, &foo_s::a);
   print_field(&my_foo, &foo_s::b);
   print_field(&my_foo, &foo_s::c);

   return 0;
}

Its output is:

field: 1 - a                                                                                                                                                                                                              
field: 1 - b                                                                                                                                                                                                              
field: 1 - c  

I'm having a bit of trouble understanding the specifics of what's going on in the print_field() function. Namely:

  1. What's the type of field? I imagine it's pointer-to-string-foo_s-member
  2. Why is the value of field always the same (1 in this case), yet foo->*field yields different results?

Mainly, I'm baffled at #2. I imagined field would be an "offset" from the start of the struct and foo->*field would have been conceptually equivalent to something like

char* ptr = static_cast<char*>(foo);
ptrdiff_t offset = somehow_get_the_byte_offset_from_pointer_to_member(field);
ptr = ptr[offset];
string result = *static_cast<string*>(ptr);

but that seems to be out since field's value doesn't vary across calls. What am I missing? How exactly is this specific operation described by the standard?

like image 974
anthonyvd Avatar asked May 15 '15 14:05

anthonyvd


People also ask

How to get a value from a pointer?

To get the value pointed to by a pointer, you need to use the dereferencing operator * (e.g., if pNumber is a int pointer, *pNumber returns the value pointed to by pNumber .

Is struct variable a pointer?

Like every other data type, structure variables are stored in memory, and we can use pointers to store their addresses. Structure pointer points to the address of the structure variable in the memory block to which it points. This pointer can be used to access and change the value of structure members.

Are structs passed by value in C?

In C, all arguments are passed to functions by value, including structs. For small structs, this is a good thing as it means there is no overhead from accessing the data through a pointer.

Can a struct be null in C?

3 answers. It is not possible to set a struct with NULL as it is declared. Fila f = NUll; error: invalid initializer. So cast% from% to NULL , which is not even a type in this code, or assign Fila to a primitive type variable is "wrong".


2 Answers

There's no overload for << to format the value of a member pointer, so you won't get anything particularly useful if you try. There is an overload for bool, and member pointers are convertible to bool, so that is what happens here. The pointer isn't null, so it converts to true, which by default is formatted as 1.

To demonstrate further, you could try streaming boolalpha first; then you should see true rather than 1.

like image 92
Mike Seymour Avatar answered Nov 15 '22 18:11

Mike Seymour


  1. The type of field is, as you say, a pointer to a member of foo_s of type std::string.

  2. The value of field is 1 in all of these cases, because pointers to member are convertible to bool, so when you output them, you get a 1 because they are not null.

like image 27
TartanLlama Avatar answered Nov 15 '22 19:11

TartanLlama