你如何在 C 中获取倒置复合垃圾的地址?

How do you take the address of an inverted compound litteral in C?

我不太确定我应该为这个问题使用什么标题,但我会尝试通过解释来澄清:

总而言之,我想要一个函数参数接受一个数组和一个整数作为同一个参数。不太难,只需要使用指针就可以了?所以我有这个:

#define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(&BIT0);
}

对于常规值,一切都很好,花花公子,但在我的情况下,我需要能够反转值,所以我认为这会起作用:

#define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(&~BIT0);
}

传递时只需用按位非(~)反转值。没什么大不了的吧?好吧,我得到了错误

error: lvalue required as unary '&' operand

如果我改写为:

#define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(&(unsigned char){~BIT0});
}

首先,这是一个非常丑陋的解决方案,我真的不想在我的代码中使用它。感觉一点都不直观。 其次,它按我最初希望的方式工作,但我认为这告诉我的是“~”运算符正在将 unsigned char 提升为 unsigned int。所以我必须将它转换回 unsigned char 函数才能接受地址。但是错误消息与令我困惑的消息并不完全匹配。

这是怎么回事?我该如何解决这个问题以获得我想要的行为?

错误的原因是某些运算符(如一元*)return一个so-called可修改的lvalue,意思是引用到您可以更改的对象。然而,大多数运算符不这样做,~ 就是这样的运算符。您从中得到的只是一个临时 read-only 值。它确实也将操作数提升为有符号 int,这通常是有问题的,但不是错误的原因。

至于如何解决问题,就看你如何使用这些宏了。如果 BIT0 是一个设置了位 0 的复合文字,那么为了保持一致,人们可能会创建一个类似的宏:

#define BITS1_7 (unsigned char){0xFE}

(注意二进制文字不是标准的 C。)

但我也不会那样做。问题的根源在于过度设计和坚持以奇怪的方式使用复合文字。而是应用 KISS principle。如果您有一个接受单个字节或数组的函数,那么编写程序的最易读的方式是:

#define BIT0 (1u << 0) // industry de facto standard way to write a bit mask
...

uint8_t tmp = BIT0;
foo(&tmp);

或者

uint8_t tmp = ~BIT0;

所有 C 程序员都可以阅读和理解这段代码。