Passing reference of packed struct member to template. gcc bug?

心已入冬 提交于 2020-01-29 05:15:08

问题


I encountered a problem, passing struct member to a template function. The function's goal is to take the address and size of the member. Here is simple example:

This is the struct. It has packed attribute.

struct TestStruct {
    unsigned char       elem1;
    unsigned char       elem2;
    uint64_t            elem3;
    char                buf[10000];
    int                 elem4;
    unsigned char       elem5;
}
__attribute__ ((packed));

this is the template function, which should get a member's address

template<typename T>
void addData(const T &val)
{
        printf ("address inside func: %p \n",&val);
}

int main(int argc, char *argv[])
{
        TestStruct testdata;
        testdata.elem4 = 0;
        printf ("struct address is:   %p \n",&testdata);
        printf ("elem4  address is:   %p \n",&testdata.elem4);
        addData(testdata.elem4);
        return 0;
}

The problem: When attribute ((packed)); is set (like in the example) the template function receives wrong address of the member:

Output:

struct address is:   0x7fff735bb4e0 
elem4  address is:   0x7fff735bdbfa 
address inside func: 0x7fff735bb4dc

If I remove the "packed" attribute, everything is OK. There is no error and no warning (even with -Wall -Wextra), but not the right address is passed to the function.

I read this:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566

and found that there is an issue, getting references to packed-struct members. Interesting enough, replacing const T& with T& in my template function, produces the error message:

error: cannot bind packed field ‘testdata.TestStruct::elem4’ to ‘int&’

So, I have 2 questions:

  1. Why cannot packed-struct members be passed as const references, when their address can be passed as pointer

  2. What happens in the const T& case? There is no error, no warning, but the incorrect address is passed to the function. As we know, the address of reference is the address of the variable, the reference points to.


回答1:


Both of your questions are answered at the link you posted.

1. Why cannot packed-struct members be passed as const references, when their address can be passed as pointer

Gabriel M. Beddingfield wrote in his comment:

All assignments of obj.s to type short& and short* are incorrect, and ideally they would all result in compiler errors.

The C++ spec (C++03, Sects. 3.9, 3.9.1, 3.9.2) are very clear that T and "pointer to T" have implementation-specific alignment requirements. If you have a "pointer to T" then you may assume that it meets the alignment requirements. I'm sure the C spec has similar language.

I can only add to this the corresponding quote from C++14 standard ([basic.align]/1):

Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment specifier

The bottom line of it is that even taking an addres of a packed struct member should be an error.

2. What happens in the const T& case? There is no error, no warning, but the incorrect address is passed to the function. As we know, the address of reference is the address of the variable, the reference points to.

Jonathan Wakely wrote:

A const-reference causes a temporary to be created, you didn't bind to the packed field


The bottom line is that it's not a bug itself that you can't bind a non-const reference to a packed struct field, a bug is that at the same time you can take an address of it. The compiler should either allow or disallow both.



来源:https://stackoverflow.com/questions/29340160/passing-reference-of-packed-struct-member-to-template-gcc-bug

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!