"Yêu cầu thành viên" ******* "trong một cái gì đó không phải là một cấu trúc hoặc công đoàn" có nghĩa là gì?


81

Có một lời giải thích dễ dàng cho lỗi này có nghĩa là gì?

request for member '*******' in something not a structure or union

Tôi đã gặp nó vài lần trong thời gian tôi học C, nhưng tôi không có manh mối về ý nghĩa của nó.


Câu trả lời tốt hơn nên được chấp nhận ở trên cùng.
T.Woody

Câu trả lời:


115

Điều này cũng xảy ra nếu bạn đang cố gắng truy cập một phiên bản khi bạn có một con trỏ và ngược lại:

struct foo
{
  int x, y, z;
};

struct foo a, *b = &a;

b.x = 12;  /* This will generate the error, should be b->x or (*b).x */

Như đã chỉ ra trong một nhận xét, điều này có thể trở nên nghiêm trọng hơn nếu ai đó đi và một typedefcon trỏ, tức là bao gồm *trong một typedef, như vậy:

typedef struct foo* Foo;

Bởi vì sau đó bạn nhận được mã trông giống như nó đang xử lý các phiên bản, trong khi thực tế nó đang xử lý các con trỏ:

Foo a_foo = get_a_brand_new_foo();
a_foo->field = FANTASTIC_VALUE;

Lưu ý cách ở trên trông như thể nó nên được viết a_foo.field, nhưng điều đó sẽ không thành công vì Foolà một con trỏ tới cấu trúc. Tôi khuyên chống lại typedef : con trỏ ed trong C. Pointers là quan trọng, đừng giấu dấu sao của bạn. Hãy để chúng tỏa sáng.


8
Tôi cá rằng đây là vấn đề thực tế. Thỉnh thoảng nó vẫn cắn tôi, đặc biệt nếu ai đó đã gõ một kiểu con trỏ.
John Bode

2
Tôi chỉ muốn nói thêm rằng lỗi này sẽ xuất hiện nếu một mảng chưa được cấp phát (malloc) và được truy cập.
tối đa

Tôi biết nó đã được khoảng một thập kỷ hoặc hơn kể từ khi bài đăng này được đăng, nhưng hai câu cuối cùng đã làm cho đây là bài đăng yêu thích mới của tôi. "Con trỏ rất quan trọng, đừng giấu dấu hoa thị của bạn. Hãy để chúng tỏa sáng."
Aiden Blishen Cuneo

20

Bạn đang cố gắng truy cập một thành viên của một cấu trúc, nhưng trong một cái gì đó không phải là cấu trúc. Ví dụ:

struct {
    int a;
    int b;
} foo;
int fum;
fum.d = 5;

5

Nó cũng có thể xảy ra trong trường hợp sau:

ví dụ. nếu chúng ta xem xét chức năng đẩy của một ngăn xếp:

typedef struct stack
{
    int a[20];
    int head;
}stack;

void push(stack **s)
{
    int data;
    printf("Enter data:");
    scanf("%d",&(*s->a[++*s->head])); /* this is where the error is*/
}

main()
{
    stack *s;
    s=(stack *)calloc(1,sizeof(stack));
    s->head=-1;
    push(&s);
    return 0;
}

Lỗi là ở chức năng đẩy và ở dòng nhận xét. Con trỏ sphải được đưa vào trong dấu ngoặc đơn. Mã chính xác:

scanf("%d",&( (*s)->a[++(*s)->head]));

2
Cảm ơn bạn đã làm rõ quan điểm (không có trò chơi gì ghê gớm về ngôn ngữ). Các câu trả lời khác đã đề cập đến vấn đề này (ví dụ: "để con trỏ của bạn tỏa sáng") nhưng vào lúc 2 giờ sáng đang vật lộn trong trận chiến hoành tráng với GDB và Valgrind, những người như tôi đánh giá cao rằng câu trả lời của bạn cho thấy rõ ràng con trỏ có thể là một vấn đề và cách khắc phục vấn đề đó .
Max von Hippel

3

Tôi đã liệt kê tất cả các trường hợp có thể xảy ra lỗi này trong mã và nhận xét của nó bên dưới. Hãy thêm vào nó, nếu bạn gặp nhiều trường hợp hơn.

#include<stdio.h>
#include<malloc.h>

typedef struct AStruct TypedefedStruct;

struct AStruct
{
    int member;
};

void main()
{
    /*  Case 1
        ============================================================================
        Use (->) operator to access structure member with structure pointer, instead
        of dot (.) operator. 
    */
    struct AStruct *aStructObjPtr = (struct AStruct *)malloc(sizeof(struct AStruct));
    //aStructObjPtr.member = 1;      //Error: request for member ‘member’ in something not 
                                      //a structure or union. 
                                      //It should be as below.
    aStructObjPtr->member = 1;
    printf("%d",aStructObjPtr->member); //1


    /*  Case 2
        ============================================================================
        We can use dot (.) operator with struct variable to access its members, but 
        not with with struct pointer. But we have to ensure we dont forget to wrap 
        pointer variable inside brackets.
    */
    //*aStructObjPtr.member = 2;     //Error, should be as below.
    (*aStructObjPtr).member = 2;
    printf("%d",(*aStructObjPtr).member); //2


    /* Case 3
       =============================================================================
       Use (->) operator to access structure member with typedefed structure pointer, 
       instead of dot (.) operator. 
    */
    TypedefedStruct *typedefStructObjPtr = (TypedefedStruct *)malloc(sizeof(TypedefedStruct));
    //typedefStructObjPtr.member=3;  //Error, should be as below.
    typedefStructObjPtr->member=3;
    printf("%d",typedefStructObjPtr->member);  //3


    /*  Case 4
        ============================================================================
        We can use dot (.) operator with struct variable to access its members, but 
        not with with struct pointer. But we have to ensure we dont forget to wrap 
        pointer variable inside brackets.
    */
    //*typedefStructObjPtr.member = 4;  //Error, should be as below.    
    (*typedefStructObjPtr).member=4;
    printf("%d",(*typedefStructObjPtr).member);  //4


    /* Case 5
       ============================================================================
       We have to be extra carefull when dealing with pointer to pointers to 
       ensure that we follow all above rules.
       We need to be double carefull while putting brackets around pointers.
    */

    //5.1. Access via struct_ptrptr and  ->
    struct AStruct **aStructObjPtrPtr = &aStructObjPtr;
    //*aStructObjPtrPtr->member = 5;  //Error, should be as below.
    (*aStructObjPtrPtr)->member = 5;
    printf("%d",(*aStructObjPtrPtr)->member); //5

    //5.2. Access via struct_ptrptr and .
    //**aStructObjPtrPtr.member = 6;  //Error, should be as below.
    (**aStructObjPtrPtr).member = 6;
    printf("%d",(**aStructObjPtrPtr).member); //6

    //5.3. Access via typedefed_strct_ptrptr and ->
    TypedefedStruct **typedefStructObjPtrPtr = &typedefStructObjPtr;
    //*typedefStructObjPtrPtr->member = 7;  //Error, should be as below.
    (*typedefStructObjPtrPtr)->member = 7;
    printf("%d",(*typedefStructObjPtrPtr)->member); //7

    //5.4. Access via typedefed_strct_ptrptr and .
    //**typedefStructObjPtrPtr->member = 8;  //Error, should be as below.
    (**typedefStructObjPtrPtr).member = 8;
    printf("%d",(**typedefStructObjPtrPtr).member); //8

    //5.5. All cases 5.1 to 5.4 will fail if you include incorrect number of *
    //     Below are examples of such usage of incorrect number *, correspnding
    //     to int values assigned to them

    //(aStructObjPtrPtr)->member = 5; //Error
    //(*aStructObjPtrPtr).member = 6; //Error 
    //(typedefStructObjPtrPtr)->member = 7; //Error 
    //(*typedefStructObjPtrPtr).member = 8; //Error
}

Các ý tưởng cơ bản rất rõ ràng:

  • Sử dụng .với biến cấu trúc. (Trường hợp 2 và 4)
  • Sử dụng ->với con trỏ đến cấu trúc. (Trường hợp 1 và 3)
  • Nếu bạn tiếp cận biến cấu trúc hoặc con trỏ tới biến cấu trúc bằng cách sau con trỏ, thì hãy bọc con trỏ bên trong dấu ngoặc vuông: (*ptr).(*ptr)->vs *ptr.*ptr-> (Tất cả các trường hợp trừ trường hợp 1)
  • Nếu bạn đang tiếp cận bằng cách theo dõi các con trỏ, hãy đảm bảo rằng bạn đã truy cập chính xác con trỏ tới struct hoặc struct tùy theo ý muốn. (Trường hợp 5, đặc biệt là 5,5)

1

Nó có thể có nghĩa là bạn đã quên bao gồm một tệp tiêu đề xác định cấu trúc / liên hiệp này. Ví dụ:

tệp foo.h:

typedef union
{
    struct
    {
        uint8_t FIFO_BYTES_AVAILABLE    : 4;
        uint8_t STATE                   : 3;
        uint8_t CHIP_RDY                : 1;
    };
    uint8_t status;
} RF_CHIP_STATUS_t;

RF_CHIP_STATUS_t getStatus();

tệp main.c:

.
.
.
if (getStatus().CHIP_RDY) /* This will generate the error, you must add the  #include "foo.h" */
.
.
.

0

cũng có thể xuất hiện nếu:

struct foo {   int x, int y, int z }foo; 

foo.x=12

thay vì

struct foo {   int x; int y; int z; }foo; 

foo.x=12

Không có sự khác biệt giữa hai tuyên bố này?
Nick Predey

1
@AlaaM. nhìn lại nó nhiều tháng sau, tôi đã bỏ lỡ các dấu chấm phẩy!
Nick Predey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.