Memory Rust-repr(C)是预处理器指令吗?

Memory Rust-repr(C)是预处理器指令吗?,memory,rust,Memory,Rust,我见过一些Rust代码库使用#[repr(C)]宏(这就是它的名称吗?),但是,我找不到太多信息,只是它将内存中的类型布局设置为与“C”相同的布局 我想知道的是:这是一个仅限于编译器而非语言本身的预处理器指令(即使没有其他编译器前端支持Rust),为什么Rust的内存布局与Cs的内存布局不同?(只是我从来没有用过另一种语言)。谢谢 编辑:这里有一个很好的情况来证明我的意思;如果有人为Rust创建了另一个编译器,那么他们需要实现这个宏吗?或者它是编译器特有的东西吗?#[repr(C)]不是预处理器

我见过一些Rust代码库使用
#[repr(C)]
宏(这就是它的名称吗?),但是,我找不到太多信息,只是它将内存中的类型布局设置为与“C”相同的布局

我想知道的是:这是一个仅限于编译器而非语言本身的预处理器指令(即使没有其他编译器前端支持Rust),为什么Rust的内存布局与Cs的内存布局不同?(只是我从来没有用过另一种语言)。谢谢

编辑:这里有一个很好的情况来证明我的意思;如果有人为Rust创建了另一个编译器,那么他们需要实现这个宏吗?或者它是编译器特有的东西吗?

#[repr(C)]
不是预处理器指令,因为Rust不使用预处理器1。这是一个很好的例子。Rust没有完整的规范,但有
repr
属性,因此它绝对是语言的一部分。在实现方面,属性的解析方式与所有其他Rust代码相同,并存储在同一AST中。Rust没有“属性传递”:属性是语言的实际部分。如果其他人要实现Rust编译器,他们需要实现
#[repr(C)]

此外,
#[repr(C)]
如果没有一些编译器的魔力就无法实现。在没有
#[repr(…)]
的情况下,Rust编译器可以随意安排
结构
/
枚举
的字段(并且可以利用这一点进行优化!)

Rust确实有充分的理由使用它自己的内存布局。如果编译器与源代码中写入结构的方式无关,则编译器不会存储从不读取的字段,不会对字段进行重新排序以获得更好的性能,
enum
标记池2,也不会在结构中的整个结构中使用备用位来存储数据(最后一个还没有发生,但将来可能会发生)。但主要原因是Rust有一些在C中没有意义的东西。例如,Rust有零大小的类型(如
()
[i8;0]
),
trait
vtables,
enum
s,带有字段和泛型类型,所有这些在尝试将它们转换为C时都会导致问题


1好的,如果你真的想,你可以用带锈的C预处理器。请不要

2例如,
enum Food{Apple,Pizza(Topping)}enum Topping{菠萝,蘑菇,大蒜}
可以存储在1字节中,因为只有4个可能的
Food
值可以创建。

这是什么? 它不是宏,而是属性

这本书对宏是什么有一个明确的定义,并提到有“类似属性的宏”:

术语宏是指Rust中的一系列功能:具有宏规则的声明性宏和三种程序性宏:

  • 自定义#[derive]宏,指定添加了用于结构和枚举的派生属性的代码
  • 定义可用于任何项目的自定义属性的类属性宏
  • 类似函数的宏,看起来像函数调用,但在指定为其参数的标记上操作
类属性宏是您可以使用的类属性。例如:

#[路由(获取“/”)]
fn索引(){}

它看起来确实像
repr
属性,不是吗
repr(C)是预处理器指令吗?
Rust有预处理器吗?什么样的“预处理器”你有什么想法吗?@KamilCuk我想我在这里使用了错误的术语,如果你知道正确的术语,请一定纠正我,但我的意思是编译器前端会预处理此布局中应用此宏的结构,然后进行编译/优化。当然,这是编译器所做的-处理文本和然后生成代码。
它们是必需的吗
-嗯,没有“铁锈警察”如果你没有实现它,那就好了……只是一个小小的旁注,
#pragma
。虽然
#pragma
是预处理指令,但编译器必须在预处理器之后做出决定,因为函数中的
#pragma STDC FENV_对
的访问只影响该函数,因此它需要知道函数何时结束,这不是预处理器所做的。这是一个很好的解释。我很惊讶Rust编译器已经在做这样的优化。但是我不能保证你不使用C预处理器;)