“强”通过单元素结构在 C 中键入。编译器会做什么?

Mar*_* A. 1 c struct padding strong-typing c89

我计划在我的 C 代码中使用包含标量字段的结构来执行一些语义强类型。基本思想是用于廉价“操作”的宏,这将在错误命名的结构字段上失败,当然还有通过严格参数列表的更复杂的函数。

示例(只有基本思想 - 不是特别聪明的宏代码)

typedef struct {float32_t speedval} MySpeed_t;
typedef struct {float32_t timeval} MyTime_t;
typefed struct {float32_t accvalue} MyAcceleration_t;

#define ACC_VEL_DT(acc,vel,time)\
          (((acc).accvalue = (vel).speedval / (time).timeval)), (acc))

#define ADD_SPEED(velres, vel1, vel2) \
           (((velres).speedval = (vel1).speedval + (vel2).speedval), (velres))

unint8 someCleverMathAndCheck(MySpeed_t speed, MySpeed_t speedArr[], MyAcceleration_t);
Run Code Online (Sandbox Code Playgroud)

现在,在处理此类 onelement 结构时,我对编译器有何期望?我是否必须期待一些填充,更复杂的 asm 来“取消引用第一个元素”,或者在使用这些构造作为函数参数时出现可怕的事情?标准是怎么说的?

Yuu*_*shi 5

不会有任何额外的填充。根据标准,结构的地址是其第一个元素的地址,因此填充始终插入在元素之间或结构的末尾,而不是开头。此外,您不必担心末尾的额外填充,因为对齐方式将正是(单个)数据类型所需的对齐方式。

打开优化后,您可以期望编译器生成基本相同的汇编代码。例如,O2 上的(32 位)GCC 生成的代码为:

float add(float a, float b)
{
    return a + b;    
}
Run Code Online (Sandbox Code Playgroud)

好像:

_add:
LFB0:
    .cfi_startproc
    flds    8(%esp)
    fadds   4(%esp)
    ret
    .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

如果您定义类似以下内容:

typedef struct foo
{
    float x;
} foo;

foo add(foo a, foo b)
{
    foo f; 
    f.x = a.x + b.x;
    return f;
}
Run Code Online (Sandbox Code Playgroud)

用O2编译,程序集是完全一样的。