【问题标题】:Why doesn't unsigned typeof(var) work? const typeof(x) works fine, so why not?为什么 unsigned typeof(var) 不起作用? const typeof(x) 工作正常,为什么不呢?
【发布时间】:2021-05-04 18:10:30
【问题描述】:

在宏中,我希望使值具有相同的宽度,但无符号。所以,一个自然的unsigned typeof(x) 浮现在脑海中。但是,它不能编译:

/home/guest/mc.c: In function ‘main’:
/home/guest/mc.c:14:36: error: expected ‘)’ before ‘typeof’
   14 |                         *((unsigned typeof(minus)*)&minus));

我想知道为什么会这样?也许我做错了什么?我可以以某种方式将unsigned 添加到变量的类型中吗?

PS。我已经注意到,添加const 的类似演员可以正常工作:

#define add_const(x) ((const typeof(x))(x))

另外,添加* 来创建指针类型也可以。

【问题讨论】:

  • unsigned typeof(x) --> typeof(unsigned x)
  • @DavidRanieri:但是x 是一个变量,而不是一个类型。在myvar 前面加上unsigned 会做什么?
  • typeof 不是 C,它是编译器扩展。 unsignedconst* 非常不同,看看它们如何使用 typedef 名称(提示:与 typeof 完全相同)。
  • 我假设这篇文章是指 GCC 扩展 typeof,并更改了标签。在讨论 C 语言的特定扩展时,请说明您使用的是哪个编译器。
  • @n.'pronouns'm.: typeof 是 C per C 2018 4 7,它有效地将符合标准的编译器的所有扩展定义为符合标准的代码。 C 的设计不像 Java 那样程序应该普遍地移植到不同的实现中。它旨在实现可移植到不同的系统和环境。这就是为什么它允许int 的宽度和许多其他选项的灵活性。扩展是 C 的一个正常、预期和期望的部分。C 提供了一种基础语言,人们可以舒适地使用它进行编程,同时还可以使用对他们的需求有用的扩展。

标签: c gcc casting unsigned typeof


【解决方案1】:

看起来唯一的方法是在一个泛型选择中枚举所有“有趣”的类型。

#define to_unsigned(x) _Generic((x),     \
                char: (unsigned char     )(x),     \
         signed char: (unsigned char     )(x),     \
                 int: (unsigned int      )(x),     \
               short: (unsigned short    )(x),     \
                long: (unsigned long     )(x),     \
           long long: (unsigned long long)(x),     \
             default: x)

short a;
typeof(to_unsigned(a)) ua;

这是不可移植的,因为实现可以提供更多的整数类型。但是 typeof 本身是特定于 gcc 的。由于 gcc 似乎提供所有其他标准整数类型(size_tuint8_t 等)作为 typedef 名称而不是单独的不同类型,因此这些情况应该涵盖所有内容。

【讨论】:

  • 如果我们假设没有填充,#define to_unsigned(x) ((uintmax_t) (x) & ((uintmax_t) 2 << sizeof (x) * CHAR_BIT - 1) - 1) 应该会产生所需的值,尽管并不总是在所需的类型中。 (请注意,2 << bits-1 用于避免按类型中的全部位数进行移位,如果类型为 uintmax_t,则未定义。)
  • @EricPostpischil 但我们需要一个类型,而不是一个值。
  • 问题的第一句话说他们想要一个所需宽度的值。这是模棱两可的,因为值是没有宽度的抽象事物,而类型有宽度。但是获得期望的值有实际用途,而获得特定类型并没有太大用处,因为正确的值将在许多地方服务,而不管有更广泛的类型。所以我会赌价值是实际目标而不是类型。
【解决方案2】:

unsigned typeof(x) 不起作用但const typeof(x) 起作用的根本原因是unsignedconst 是两个不同的语法组件。 unsigned 是类型说明符,而 const 是类型限定符。

类型说明符列表(请注意,unsigned 在语法上等同于 unsigned int

6.7.2 Type specifiers

1. 语法

      type-specifier:
             void
             char
             short
             int
             long
             float
             double
             signed
             unsigned
             _Bool
             _Complex
             atomic-type-specifier
             struct-or-union-specifier
             enum-specifier
             typedef-name

2. 约束

...

  • 无符号或无符号整数

所以unsigned typeof(x) 等同于unsigned int typeof(x)

const 是一个类型限定符:

6.7.3 Type qualifiers

1. 语法

      type-qualifier:
             const
             restrict
             volatile
             _Atomic

const char 是正确的 C 代码,假设 xcharunsigned int char 不是正确的 C 代码。

【讨论】:

    【解决方案3】:

    为什么 unsigned typeof(var) 不起作用? const typeof(x) 工作正常,为什么不呢?

    clause 6.7 of the GCC 10.2 documentation:

    typeof 构造可用于任何可以使用 typedef 名称的地方。

    在 C 2018 6.7 中指定的声明的 C 语法中,声明说明符被划分为类:

    • 存储类说明符,例如 staticextern
    • 类型说明符,例如 intfloat
    • 类型限定符,例如 constvolatile
    • 函数说明符,例如inline
    • 对齐说明符,例如_Alignas(4)

    第 6.7.2 条表明 typedef-name 是类型说明符。第 2 段规定了它们的使用方式。它给出了允许的组合列表,包括:

    • intsignedsigned int
    • unsigned,或unsigned int
    • 类型定义名称

    因此,unsigned 只能用于此列表中显示的特定组合,例如unsigned long long。 typedef 名称本身显示为一个项目,没有unsigned。所以不能和unsigned一起使用。

    相比之下,const 是一个限定符,它是一种不同的说明符,6.7 的其他条款允许混合不同种类的说明符(有一些在这里不相关的附加限制,例如具有 at最多一个存储类说明符)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 2012-02-14
      相关资源
      最近更新 更多