【问题标题】:Hide single item on a struct隐藏结构上的单个项目
【发布时间】:2019-12-11 01:32:16
【问题描述】:

我需要在一个结构中隐藏一个单个字段,而不是多个:

struct MyType1
{
   unsigned char Value;
}; //

struct MyType2
{
   unsigned void* Value;
} ; //

struct MyType3
{
  signed int;
} ; //

如果可能的话,我希望结构类型与原始类型变量具有相同的大小,但编译器将其视为新类型。

在代码的某些部分我想回退结构, 到简单的值。

还可以创建具有这种结构类型的数组,但是, 空间不大。

MyType1 MyArray[255];

我已经查过以前的答案,但是没有找到。

例子:

typedef
   unsigned int /* rename as */ mydatetime;

// Define new type as
struct mydatetimetype
{
  unsigned int /* field */ value;
} ;

假设我在同一个程序中有这些功能,但包含文件不同:

void SomeFunc ( unsigned int /* param */ anyparam );

void SomeFunc ( mydatetime /* param */ anyparam );

void SomeFunc ( mydatetimetype /* param */ anyparam );

我的编程编辑器或 I.D.E.混淆了前两个功能。

稍后,在代码的某些部分,我将使用带有整数运算的压缩类型,但我应该对其他使用这种类型的程序员隐藏。

请注意,我还想将此功能应用于其他类型,例如指针或字符。

而且,不需要“转发”或使用“不透明”结构。

单个字段结构如何被填充或打包?

我应该添加一个属性来打包或填充这个结构以获得更好的性能吗?

这个技巧已经有名字了吗?

【问题讨论】:

  • 这完全取决于实现。您正在寻找的技术通常称为“强类型定义”。
  • 为什么您需要“在结构中隐藏单个项目...”?您需要解决的实际问题是什么?
  • 我只是好奇,为什么要将变量隐藏在struct 中?
  • 你为什么不尝试使用联合?
  • MSVC 是您的 IDE 吗?在最后一个示例中,您展示了两个具有相同签名的函数和一个 重载 的函数。

标签: c strong-typing


【解决方案1】:

希望下面的代码可以帮到你。

代码向您展示了如何使用union 来获得更多类型使用相同的内存空间。

这段代码的结果可能是依赖于实现的,无论如何它向你展示了在integersunion中指定的所有类型共享相同的内存空间。

声明为integers(在代码中为k)的变量总是 long 作为声明中的较长类型。然后我们知道,在代码中,变量k 可能包含从 8 位到 64 位的整数类型,始终使用 64 位。

虽然我只使用整数类型,但您可以在 union 声明中使用的类型可以是您想要的任何类型,也可以是 struct 类型和/或指针。

#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

typedef union integers {
    int8_t i8;
    int16_t i16;
    int32_t i32;
    int64_t i64;
    } integers;

typedef struct sInt {
    integers a;
    integers b;
} sInt;

int main(void) {
    integers k;
    sInt s;

    k.i64=0x1011121314151617;

    printf("Int 08: %" PRIx8 "h\n", k.i8 );
    printf("Int 16: %" PRIx16 "h\n", k.i16 );
    printf("Int 32: %" PRIx32 "h\n", k.i32 );
    printf("Int 64: %" PRIx64 "h\n", k.i64 );

    s.a.i64=0x1011121314151617;
    s.b.i64=0x0102030405060708;

    printf("Int a.08: %" PRIx8 "h\n", s.a.i8 );
    printf("Int a.16: %" PRIx16 "h\n", s.a.i16 );
    printf("Int a.32: %" PRIx32 "h\n", s.a.i32 );
    printf("Int a.64: %" PRIx64 "h\n", s.a.i64 );

    printf("Int b.08: %" PRIx8 "h\n", s.b.i8 );
    printf("Int b.16: %" PRIx16 "h\n", s.b.i16 );
    printf("Int b.32: %" PRIx32 "h\n", s.b.i32 );
    printf("Int b.64: %" PRIx64 "h\n", s.b.i64 );

    return 0;
}

注意:如果您的问题是结构中的填充,则此代码并不完全是您要寻找的答案。要管理填充,您必须使用#pragma pack()(gcc 和其他编译器管理#pragmas)

【讨论】:

  • 谢谢,我会运行代码,稍后,看起来很详细。
  • 谢谢。但是,在这种情况下,我需要一个独立于其他变量的字段。
  • 您是说您需要使用k 而不是k.i8k.i16
  • "要管理填充,您必须使用 #pragma push()#pragma pop" 您似乎将此与 pack(n) and pack() 混淆了?
  • 请原谅我的垃圾。我编辑了。我对 pack 的语法感到困惑。
【解决方案2】:

可以填充结构以对齐地址边界。因此,您的第一个和第三个结构更可能不会具有与原始类型相同的大小。

单字段结构更有可能在字段“后面”填充,但 C 标准并未说明编译器应如何执行此操作。

如果你想将你的结构转换为原始类型,你应该添加 attribute(以确保你正在转换它存储的值而不是填充中的垃圾)但是,我认为(并且 不要 推荐)即使没有 属性 也可以将结构转换为变量并获得正确的结果(尽管它非常依赖于实现)。但是,每次处理器尝试从内存中加载非对齐结构时,您都会受到很小的性能损失。

另外你应该小心,because 打包结构可能很危险

【讨论】:

  • “所以你的第一个和第三个结构更可能不会有与原始类型相同的大小。” 你有现代实现的例子吗?完整结构的对齐限制由其成员决定,在典型的现代实现中,具有单个成员的结构不应有任何理由添加填充。
  • @user694733 是的,没错,现代编译器都没有这样做。我tested.
  • 为了完整性:C 标准保证在struct 的第一个元素之前 永远不会有任何填充。
猜你喜欢
  • 2020-08-03
  • 2014-10-26
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多