【问题标题】:How do I fix an error in a header file typedef struct (expected a ";")?如何修复头文件 typedef 结构中的错误(应为“;”)?
【发布时间】:2020-08-16 21:38:44
【问题描述】:

我从 github https://github.com/fabvalaaah/rlec 下载了这个项目,并且在 bitmap.h 中 typedef 结构中有错误(应为“;”)。在项目的其余部分中,_bitmap 存在错误(标识符未定义)。我正在使用 Visual Studio 2019。如何解决?

#ifndef BITMAP_H
#define BITMAP_H

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>

#include "common.h"

const uint8_t lineFeed;
const uint8_t imageEnd;

typedef struct __attribute__((__packed__)) _bitmap{ //Error is here on _bitmap
    uint8_t magicNumber[2];
    uint32_t size;
    uint8_t reserved[4];
    uint32_t startOffset;
    uint32_t headerSize;
    uint32_t width;
    uint32_t height;
    uint16_t planes;
    uint16_t depth;
    uint32_t compression;
    uint32_t imageSize;
    uint32_t xPPM;
    uint32_t yPPM;
    uint32_t nUsedColors;
    uint32_t nImportantColors;
}
_bitmap;

void printHeader(_bitmap* image);
int RLECompression(FILE* ptrIn, FILE* ptrOut);
int RLEDecompression(FILE* ptrIn, FILE* ptrOut);

#endif /* BITMAP_H */

【问题讨论】:

  • edit您的问题,以便您可以复制粘贴(作为文本)您遇到的完整和完整的错误。另外,请在出现错误的显示代码中添加注释。另外请告诉我们您使用的是什么编译器,因为显示的代码包含一些可能无法在您的编译器上运行的非标准和不可移植的扩展。
  • 尝试创建一个minimal reproducible example 来向项目作者报告问题不是更好吗?
  • 哪个编译器?属性 packed 是仅 gcc 的非标准扩展,其他编译器无法识别。此外,出于多种原因,您永远不应该在头文件中声明变量。
  • 我编辑了我的问题。我正在使用 Visual Studio 2019,错误在 typedef struct 中。
  • 你的错误。如前所述,头文件使用非标准且不可移植的扩展名(__attribute__ 事物),并非在所有编译器中都可用。最值得注意的 __attribute__ 不受 Visual Studio 支持。 Visual C++ 变体是the pack pragma。您需要添加一些条件编译来选择使用哪个(并且可能向项目作者添加功能请求以添加此类)。

标签: c compiler-errors


【解决方案1】:

代码使用 gcc 扩展。所以最简单的编译方法就是使用 gcc 编译器。

但你能做的就是改变

typedef struct __attribute__((__packed__)) _bitmap{

typedef struct _bitmap{

它可能会起作用,并且可能会破坏代码,具体取决于代码其他部分发生的情况。我的猜测是它会很好地工作,但我不能保证代码的作者没有做任何“聪明”的事情。

【讨论】:

  • @viribus 如果您的问题已经解决,请随时接受答案。
  • @viribus 请注意,pack 对于获取准确的字段布局可能很重要。
【解决方案2】:
typedef struct __attribute__((__packed__)) _bitmap

这是在 GCC 中定义没有零填充的结构定义的方法。 要防止 MVSC 中的零填充,请使用 #pragma pack:

#pragma pack(push,1)
typedef struct _bitmap{ //Error is here on _bitmap
    uint8_t magicNumber[2];
    uint32_t size;
    uint8_t reserved[4];
    uint32_t startOffset;
    uint32_t headerSize;
    uint32_t width;
    uint32_t height;
    uint16_t planes;
    uint16_t depth;
    uint32_t compression;
    uint32_t imageSize;
    uint32_t xPPM;
    uint32_t yPPM;
    uint32_t nUsedColors;
    uint32_t nImportantColors;
} _bitmap;
#pragma pack(pop) 

正如你在这里看到的https://godbolt.org/z/Gr-Rsw 它编译得很好。

请注意,禁用填充很重要以获得您想要的确切结构(前 2 个字节是“幻数”,然后是 4 个字节的大小等)。在这种情况下,您可以从文件中读取第一个 sizeof(_bitmap) 字节,并期望布局与结构中定义的完全相同。

如果没有#pragma pack,这种结构的大小可能会非常基于不同的架构。例如here 的大小是 56 字节,这是因为编译器在 magicNumber[2] 之后添加了填充以将其对齐为 4 字节,而 pack 属性为 54 字节 (example)。

【讨论】:

  • 当我看到 __attribute__((__packed__))#pragma pack(push,1) 时,我想,“糟糕的代码。要么太懒要么没有足够的时间来进行正确、可靠、可移植的序列化。还有什么其他 会这么草率地做吗?”
  • @AndrewHenle 完全不同意你的观点。包装通常需要遵守一些标准协议。假设_bitmap这个结构不是你定义的,而是位图文件头或者硬件块的定义。在不打包的情况下保留结构,可能会在某些架构上导致填充,例如,在编译以获得最佳性能时 (-O3)。编译器可能会将每个结构定位在与 64 位对齐的偏移量处。
  • 通常需要打包以符合某些标准协议。“标准协议”不依赖于特定平台的实现,例如打包结构。使用打包结构序列化到标准协议或从标准协议反序列化是懒惰的,这让我想知道采取了哪些其他捷径。如果一个实现提供了一个打包的结构,它就不是可移植的,也不是标准的。
  • @AndrewHenle 相反。一旦你有一个定义的布局,你要么手动复制字段并填写结构的字段(并且这种转换应该在接收和发送数据时直接完成)或者你定义没有填充的结构然后你可以在任何方向memcopy它。我不会称之为懒惰。有时性能很重要。
  • 你定义了没有填充的结构,然后你可以在任何方向上memcopy你只是错过了必须处理字节顺序,每个标准协议都会解决这个问题。您刚刚就糟糕的代码提出了我的观点,让我想知道 else 遗漏了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多