簡體   English   中英

Typedef 用不同類型重新定義('struct TGAME' vs 'struct TGAME')

[英]Typedef redefinition with different types ('struct TGAME' vs 'struct TGAME')

我有標題的編譯錯誤。

我聽說這可能是因為我給結構起的名字,但我把它改成隨機名字太多次了,這並沒有解決。

我的 IDE (CLion),顯示 PLBR.c 中的錯誤

這是我的文件:

PLBR.h

#ifndef UNTITLED2_PLBR_H
#define UNTITLED2_PLBR_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int players;
    char diff[5];
    int numpal;
    char *palabras;
}TGAME;

PLBR.c

#include "PLBR.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct{
    int players;
    char diff[5];
    int numpal;
    char *palabras;
}TGAME;

在 main.c 我只有 #include "PLBR.h" 和一些代碼,但沒有任何關系。

簡單的部分

這是一個有趣的問題,因為要完全回答它很復雜。 讓我們從簡單的答案開始:為避免出現問題,請不要在源文件中重新定義類型。 在 header 文件中定義它並在源文件中包含 header 文件就足夠了。

復雜的部分

現在是復雜的部分。 如果將名稱重新定義為相同類型,則允許您重復typedef定義。 C 2018 6.7 3 說:

……標識符的聲明不得超過一個……除了:

— 可以重新定義 typedef 名稱以表示與當前相同的類型,前提是該類型不是可變修改的類型;…

所以,如果你有typedef int foo; 兩次或typedef char bar[3]; 兩次,那很好。 你也可以有typedef struct MyStruct foo; 兩次。

但是,您不能使用typedef struct { int i; } foo; typedef struct { int i; } foo; 兩次。 即使這兩個聲明具有相同的文本,它們也聲明了不同的類型。 這是因為 C 2018 6.7.2.3 5 中的一條規則:

… 不包含標記的結構、聯合或枚舉類型的每個聲明都聲明了不同的類型。

造成這種情況的原因有時是我們將具有相同內容的結構用於不同的目的。 例如,我們可能有一個具有兩個double值的結構,用於復數(實部和虛部)和一個具有兩個double值的結構,用於平面中的點( xy坐標):

typedef struct { double d[2]; } ComplexNumber;
typedef struct { double d[2]; } Point;

讓編譯器將這些視為不同的類型意味着它可以向我們發出有關錯誤的警告,例如將Point作為參數傳遞給期望Complex的地方。

因此,每次重復定義時,您的結構都是不同的類型。

有一種方法可以多次引用同一個結構類型,那就是給它一個標簽:

typedef struct MyTag {
    int players;
    char diff[5];
    int numpal;
    char *palabras;
} TGAME;

然后我們可以重新定義TGAME而不會出錯; typedef struct MyTag TGAME; 可能會出現,甚至多次出現,並且它將TGAME重新定義為相同的類型struct MyTag ,這是允許的。

但是,雖然可以重復typedef ,但不能重復結構定義。 如果您有兩次:

typedef struct MyTag {
    int players;
    char diff[5];
    int numpal;
    char *palabras;
} TGAME;

編譯器會抱怨。 這是因為 C 2018 6.7.2.3 說:

一個特定類型的內容最多只能定義一次。

因此,盡管您可以根據需要多次重復具有相同類型的typedef ,但不能重復完整的結構定義。 要再次使用結構類型,您只能單獨使用標記重復它,而不是使用其內容的完整定義。

綜上所述,關於結構標簽和類型的規則仍然不完整。 scope 仍有問題需要考慮。 在新的 scope 中使用struct MyTag可以引用以前的類型或創建新類型,具體取決於它的使用方式!

這是一個例子。 以下出現錯誤,因為typedef TypeA TypeB; 不會將TypeB重新定義為它最初定義為的相同類型:

typedef struct Tag { int x; } MyType;   // Create a new type.

void foo(void)  //  Start a new scope.
{
    typedef struct Tag TypeA;               // Define TypeA as previous type.
    typedef struct Tag { int x; } TypeB;    // Make a new type.
    typedef TypeA TypeB;                    // Error, TypeA is not same as TypeB.
}

但插入struct Tag; 改變意思:

typedef struct Tag { int x; } MyType;   // Create a new type.

void foo(void)  //  Start a new scope.
{
    struct Tag;                             // Declare struct Tag to be some new type.
    typedef struct Tag TypeA;               // Define TypeA as new type.
    typedef struct Tag { int x; } TypeB;    // Define new type and define TypeB to be that type.
    typedef TypeA TypeB;                    // Works, TypeA is same as TypeB.

    (void) (TypeB *) 0; // (Avoid compiler warning about unused name.)
}

您已經在TGAME中定義了PLBR.h 無需在PLBR.c中重新定義; 這樣做實際上是不允許的。

C 編譯器的第一階段之一是通過替換引用文件的內容來解釋#include...語句。 因此,當使用TGAME時,編譯器會看到:

// Contents of stdio.h
// Contents of stdlib.h
// Contents of string.h

typedef struct {
    int players;
    char diff[5];
    int numpal;
    char *palabras;
}TGAME;

typedef struct{
    int players;
    char diff[5];
    int numpal;
    char *palabras;
}TGAME;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM