代码之家  ›  专栏  ›  技术社区  ›  Christoffer Corfield Aakre

当这个C代码不包括正确的头文件时,它是如何编译的?

  •  -2
  • Christoffer Corfield Aakre  · 技术社区  · 3 年前

    我有一个来自Pokemon Emerald反编译代码库的头文件( https://github.com/pret/pokeemerald )它使用不同头文件中定义的类型,但不包括该头文件,或者包括ANY头文件,但代码仍以某种方式编译。我的neovim LSP说 u8 和 bool8 例如,由于 gba/types.h 不包括头文件。然而,由于某种原因,我使用intellisense的VScode LSP确实可以识别这些类型。有人知道这里发生了什么吗?这里是否发生了某种隐含的包含?这些类型在整个代码库中都有使用,我搜索了“ #include "gba/ ”,并且几乎没有发生。因此,这些头文件没有包含在源文件或头文件中,但无论如何,代码都会编译。

    头文件使用不包括头的类型以供参考:

    // file name: include/field_control_avatar.h
    #ifndef GUARD_FIELDCONTROLAVATAR_H
    #define GUARD_FIELDCONTROLAVATAR_H
    
    struct FieldInput
    {
        bool8 pressedAButton:1;
        bool8 checkStandardWildEncounter:1;
        bool8 pressedStartButton:1;
        bool8 pressedSelectButton:1;
        bool8 heldDirection:1;
        bool8 heldDirection2:1;
        bool8 tookStep:1;
        bool8 pressedBButton:1;
        bool8 input_field_1_0:1;
        bool8 input_field_1_1:1;
        bool8 input_field_1_2:1;
        bool8 input_field_1_3:1;
        bool8 input_field_1_4:1;
        bool8 input_field_1_5:1;
        bool8 input_field_1_6:1;
        bool8 input_field_1_7:1;
        u8 dpadDirection;
    };
    
    void FieldClearPlayerInput(struct FieldInput *pStruct);
    void FieldGetPlayerInput(struct FieldInput *pStruct, u16 keys, u16 heldKeys);
    int ProcessPlayerFieldInput(struct FieldInput *pStruct);
    void overworld_poison_timer_set(void);
    void RestartWildEncounterImmunitySteps(void);
    const u8 *GetObjectEventScriptPointerPlayerFacing(void);
    bool8 TryDoDiveWarp(struct MapPosition *position, u16 b);
    int SetCableClubWarp(void);
    u8 TrySetDiveWarp(void);
    const u8 *GetInteractedLinkPlayerScript(struct MapPosition *position, u8 metatileBehavior, u8 direction);
    u8 *GetCoordEventScriptAtMapPosition(struct MapPosition *position);
    void ClearPoisonStepCounter(void);
    
    #endif // GUARD_FIELDCONTROLAVATAR_H
    

    老实说,我并不觉得代码编译有那么奇怪,因为它使用了一个名为 agbcc ( https://github.com/pret/agbcc ),也许构建系统会自动包含这些文件。但我的VSCode LSP正在使用 clang ,但它识别这些类型而不包括标头。所以我不确定发生了什么。

    1 回复  |  直到 3 年前
        1
  •  3
  •   Mooing Duck    3 年前

    似乎几乎每个 C 该repo中的文件以开头 #include "global.h" 其开始于:

    #include <string.h>
    #include <limits.h>
    #include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines.
    #include "gba/gba.h"
    #include "constants/global.h"
    #include "constants/flags.h"
    #include "constants/vars.h"
    #include "constants/species.h"
    #include "constants/pokedex.h"
    #include "constants/berry.h"
    #include "constants/maps.h"
    #include "constants/pokemon.h"
    #include "constants/easy_chat.h"
    #include "constants/trainer_hill.h"
    

    gba/gba.h的开头是:

    #include "gba/defines.h"
    #include "gba/io_reg.h"
    #include "gba/types.h"
    #include "gba/multiboot.h"
    #include "gba/syscall.h"
    #include "gba/macro.h"
    #include "gba/isagbprint.h"
    

    因此,includes是过渡性的。

    我没有进一步研究,但大概这就是它的编译方式。

    推荐文章