天天财汇 购物 网址 万年历 小说 | 三峰软件 小游戏 视频
TxT小说阅读器
↓小说语音阅读,小说下载↓
一键清除系统垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放,产品展示↓
首页 淘股吧 股票涨跌实时统计 涨停板选股 股票入门 股票书籍 股票问答 分时图选股 跌停板选股 K线图选股 成交量选股 [平安银行]
股市论谈 均线选股 趋势线选股 筹码理论 波浪理论 缠论 MACD指标 KDJ指标 BOLL指标 RSI指标 炒股基础知识 炒股故事
商业财经 科技知识 汽车百科 工程技术 自然科学 家居生活 设计艺术 财经视频 游戏--
  天天财汇 -> 科技知识 -> 如何看待 Linux 内核邮件列表重启将内核中的 C 代码转换为 C++ 的讨论? -> 正文阅读

[科技知识]如何看待 Linux 内核邮件列表重启将内核中的 C 代码转换为 C++ 的讨论?

[收藏本文] 【下载本文】
[文章: 硬核观察 #1243 Linux 内核开发者再次讨论从 C 语言转换为现代 C++ 语言] A 2024 Discussion Whethe…
可以使用c++20子集,这样可以有静态代码分析和高效的语法,代替丑陋的宏。
内核本身很多是模拟c++,为何不直接用c++,起码内核代码清晰很多,因为是用子集,现在内核用C模拟C++ 各种大量宏真的很难看,如果用C++ 贡献者也很多。
因为 C++ 20 开始真的香啊。
甚至 NDC 在 2019 年专门有一个主题是讲用现代 C++ 来做内核编程。
你需要做的只是把 C++ 的异常删掉,再把 STL 去掉,再把默认的 new 去掉(强制 placement new),剩下的东西用来做内核编程非常舒服,比如 auto、lambda、移动语义、RAII、coroutine、placement new 和运算符重载等等,特别是 RAII 在内核编程上用处非常大,placement new 还能让你轻松在 non-paged pool 上分配内存来满足内核代码的需求。
感兴趣的可以参考:Developing Kernel Drivers with Modern C++ - Pavel Yosifovich (youtube.com)
下面要说的和内核代码没关系,但是还是想说一下,不想看这部分可以直接跳到最后一句话看结论。
隔壁 Windows 现在的新系统的用户态 API (也叫做 WinRT API)就是 C++ 20 上面构建的,MSVC 甚至从 2015 年左右就率先支持了还在草案的 coroutine,就是为了给系统 API 用。系统 API 层面直接原生支持异步,比如我现在想在 C:\Users 下创建个 hello.txt,然后往里面非阻塞地写个 Hello, World!:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage;

IAsyncAction write_file_async() {
    auto folder = co_await StorageFolder::GetFolderFromPathAsync(L"C:\\Users");
    auto file = co_await folder.CreateFileAsync(L"hello.txt", CreationCollisionOption::ReplaceExisting);
    co_await FileIO::WriteTextAsync(file, L"Hello, World!");
}

直接搞定。
你再想想用老的 Win32 API 又或者是 Linux 系统调用来实现同样的异步非阻塞读写要多少代码。
用 socket 写个异步非阻塞的 server 监听到端口 12345 上,什么 epoll、io_uring、IOCP?根本连听说都不需要听说,直接一个 StreamSocketListener 全搞定:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Networking;
using namespace Windows::Networking::Sockets;
using namespace Windows::Storage::Streams;

StreamSocketListener listener;
listener.ConnectionReceived([](StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) -> IAsyncAction {
    StreamSocket socket = args.Socket();
    IInputStream input_stream = socket.InputStream();
    co_await input_stream.ReadAsync(...);
});

co_await listener.BindEndpointAsync(nullptr, L"12345");

你敢相信这是系统 API?你敢相信这是 C++?
Windows 最初开始推广这套 API 到现在已经过去了十几年,最开始还是 UWP only,大概 2017 年左右放开给了所有类型的项目使用,于是积累了大量的生态和用户,在近些年 Windows 的 C++ 新项目里甚至已经很难找到不使用这套系统 API 的了,对于其它系统来说属于是降维打击。
现在甚至连什么 HttpClient、Json、机器学习、OCR、图片视频编解码等等一大堆 API 都进了系统 API,2024 年的今天用 C++ 做 Windows 开发,你直接 #include <winrt/...h> ,最后记得链接到 OneCore.lib 就能满足绝大多数需求。外加现在主流 C++ 编译器都支持了 C++ 20,所以无论你用什么编译器,在 Windows 上都能享受到上面这种方便快捷的开发体验,享受到接近 C# 的开发效率,C++ 的执行速度。
当然,问题中指的内核态 API 还是老样子。
总之 C++ 20 进系统带来的好处是显而易见的,我个人非常期待有一天 Windows 的内核态系统 API 也能变成这样(当然不是指把 WinRT 直接放到内核,而是指提供一套 stdcall 之外的基于现代 C++ 的 ABI,例如一个为 kernel 特化的 Kernel WinRT),当然也同时期待看到 Linux 的系统调用有一天也能变成这样。
Linux 毕竟是宏内核,仓库代码里除了内核的核心部分还包含了大量的外围代码。系统最核心的部分用 C 甚至汇编很好理解,毕竟效率至上,Windows 也是这么做的,但是那些外围的部分(比如驱动等等)换成 C++ 20 我觉得并没有任何的问题。比如在开发 Windows 驱动的时候,C 和 C++ 都能用,但用 C++ 就是比直接用 C 舒服。
理论上来讲c++的concept、modules、contract确实适合linux kernel,而且c++可以和c无缝衔接,不过这个明显是政治大过技术选择,就看各方博弈的结果。
当然举双手赞成啊。
GCC 在 12 年前就把开发语言换成 C++ 了。LLVM/Clang 一开始就是用的 C++。
看不出来内核有什么本质上的特殊性导致它不能用,只有 Linus 想不想。
Myth 1、C++ 不能用来写内核。
编译器支持 freestanding 模式就能用来写内核。GCC、Clang 都支持 C++ 的 freestanding 模式。
Myth 2、C++ ABI 太复杂/不稳定/兼容性不好,不适合内核。
ABI 问题都是 kernel 内部的,影响不到对外接口——系统调用。系统调用甚至都不是 C 接口,而是汇编接口。(libc 里面以函数形式提供的“系统调用”其实是系统调用的封装,不是系统调用本身。)
内核模块倒是真的可能受影响。但要知道,现在的 C 实现,Linux 也要求内核和模块必须使用同一编译器。换到 C++ 并不会带来更多麻烦。
另外,甚至「C++ ABI 不稳定」这个说法本身也已经可以认为是过去时了。GCC 3.4 以后就没再对 C++ 语言特性 ABI 作过不兼容的修改,GCC 5 以后没有再对标准库作过 ABI 不兼容的修改。[1]其他可以用于编译内核的编译器(Clang 完整支持、以及 ICC 有限支持)在 Linux 下的 C++ ABI 都是和 GCC 一样的。
Myth 3、C++ 的多态、异常等特性不适合内核。
异常不适合内核是真,要禁掉。
至于多态,现在的 C 代码里就充满了多态,换到 C++ 不过让编译器自动多干点活。
比如:

struct inode_operations {
	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
	const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
	int (*permission) (struct mnt_idmap *, struct inode *, int);
	struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
	/* ... */    

你可能不觉得这个 struct 有什么特殊的,其实它是一个虚表。C 里面写多态就得像这样把虚表、虚表指针等都显式写出来。
参考^有个别边缘 case 有不兼容的修改,主要都是 bugfix。
看linus的意见吧,虽然我觉得C++20挺好。但这个提案很难过linus那一关。
整个C++20子集倒是不错。但其实整体工作量挺大。
能接受。
如何看待 Linux 内核邮件列表重启将内核中的 C 代码转换为 C++ 的讨论?19 赞同 · 6 评论回答
这个回答基本是错的。
C++ 编译速度的痛点在 Rust 全都存在(C++ 有模板和实例化, Rust 同样有实现上几乎一致的泛型和单态化)。 C++ 专属的头文件问题恰好会被模块回避掉。“先是赶紧画内存安全静态检查的大饼,又在 Linus 还没走的情况下打起 Linux 内核的主意”这些事情确实发生过,而且一直在发生。但是是从 Rust 存在前就开始了。
个人观点,C 的抽象能力还是有待增强。比如 Linux VFS 部分的代码,VFS 本身的设计就特别符合 OO 的范式,Linux 里面使用了各种 *_operations 作为虚表,每个结构体包含一个 const 指针指向虚表,用这种方式实现了多态:

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *,
	...
};

struct file {
	...
	struct fown_struct	f_owner;
	const struct cred	*f_cred;
	struct file_ra_state	f_ra;
	struct path		f_path;
	struct inode		*f_inode;	/* cached value */
	const struct file_operations	*f_op;
        ...
};

struct inode_operations {
	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
	const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
	int (*permission) (struct mnt_idmap *, struct inode *, int);
	struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);

	int (*readlink) (struct dentry *, char __user *,int);

	int (*create) (struct mnt_idmap *, struct inode *,struct dentry *,
		       umode_t, bool);
	int (*link) (struct dentry *,struct inode *,struct dentry *);
	int (*unlink) (struct inode *,struct dentry *);
	int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *,
			const char *);
        ...
};

struct inode {
	umode_t			i_mode;
	unsigned short		i_opflags;
	kuid_t			i_uid;
	kgid_t			i_gid;
	unsigned int		i_flags;

#ifdef CONFIG_FS_POSIX_ACL
	struct posix_acl	*i_acl;
	struct posix_acl	*i_default_acl;
#endif

	const struct inode_operations	*i_op;
        ...
};

不仅代码冗长,而且创建这些结构体也比较麻烦。在使用 C++ 实现的内核中,处理这些抽象相对而言就比较简单了,virtual + 继承一把梭。比如 SerenityOS 中的实现

class File
    : public AtomicRefCounted<File>
    , public LockWeakable<File> {
public:
    virtual bool unref() const { return AtomicRefCounted<File>::unref(); }
    virtual void will_be_destroyed() { }
    virtual ~File();

    virtual ErrorOr<NonnullRefPtr<OpenFileDescription>> open(int options);
    virtual ErrorOr<void> close();
    ...
};

Fuchsia 中的实现也是如此。与 Linux 和 SerenityOS 不同的是,由于内核设计不同,这部分代码位于 userspace 中,而不是 zircon:

class Node {
 public:
  Node();
  virtual ~Node();

  Node(const Node&) = delete;
  Node& operator=(const Node&) = delete;

  // Notifies |Node| that it should remove and return
  // |connection| from its list as it is getting closed.
  virtual std::unique_ptr<Connection> Close(Connection* connection);

  // This function is called before |Close| is called and status is passed to
  // fuchsia::io::Node#Close| call.
  // Please note |Node| is closed even if this function returns error, so Node
  // should be ready a |Close| call.
  // Default implementation returns |ZX_OK|.
  virtual zx_status_t PreClose(Connection* connection);

  // Implementation of |fuchsia.io.Node/Describe|.
  //
  // Subclass must override this method to describe themselves accurately.
  virtual void Describe(fuchsia::io::NodeInfoDeprecated* out_info) = 0;

  // Implementation of |fuchsia.io.Node/Sync|.
  virtual zx_status_t Sync();
  ...
};

不管是用 C++、Rust、Zig 甚至是 Common Lisp (Mezzano) 都能有效化简实现。规定一套编码规范,只使用语言的一个子集,再开发一套适合内核开发的组件,三管齐下既能提升开发效率又保持了一致性。
不过话又说回来,用任何一门语言重写已有内核组件都是不现实并且收益不大的,引入新语言的目的更多是为了方便后续开发。但鉴于目前内核功能已经非常完善了,引入新语言的收益进一步下降。哪怕是之前引入的 Rust,初衷也是为了改善驱动实现的质量。再加上 C++ 本身就饱受争议,这个提案估计要么被再次搁置要么经历长时间的扯皮,短时间内 C++ 进入内核的希望渺茫。希望未来我被狠狠打脸 :P
C++20 比起 Linus 上次大喷 C++ 时的 C++03 已经有了翻天覆地的变化。但他到底会不会在项目重新考虑 C++?多说无益,我们直接对比他上次反驳的观点一一对比,看看 C++20 已经有了哪些可以让 Linus 改变心意的变化。
我们先看上次 Linus 反驳的原文('Re: [RFC] Convert builin-mailinfo.c to use The Better String' - MARC)。
这是 git 的邮件列表,代表了 Linus 对用户态底层应用中使用 C++ 的看法:

On Wed, 5 Sep 2007, Dmitry Kakurin wrote:
> 
> When I first looked at Git source code two things struck me as odd:
> 1. Pure C as opposed to C++. No idea why. Please don't talk about portability,
> it's BS.

*YOU* are full of bullshit.

C++ is a horrible language. It's made more horrible by the fact that a lot 
of substandard programmers use it, to the point where it's much much 
easier to generate total and utter crap with it. Quite frankly, even if 
the choice of C were to do *nothing* but keep the C++ programmers out, 
that in itself would be a huge reason to use C.

In other words: the choice of C is the only sane choice. I know Miles 
Bader jokingly said "to piss you off", but it's actually true. I've come 
to the conclusion that any programmer that would prefer the project to be 
in C++ over C is likely a programmer that I really *would* prefer to piss 
off, so that he doesn't come and screw up any project I'm involved with.

C++ leads to really really bad design choices. You invariably start using 
the "nice" library features of the language like STL and Boost and other 
total and utter crap, that may "help" you program, but causes:

 - infinite amounts of pain when they don't work (and anybody who tells me 
   that STL and especially Boost are stable and portable is just so full 
   of BS that it's not even funny)

 - inefficient abstracted programming models where two years down the road 
   you notice that some abstraction wasn't very efficient, but now all 
   your code depends on all the nice object models around it, and you 
   cannot fix it without rewriting your app.

In other words, the only way to do good, efficient, and system-level and 
portable C++ ends up to limit yourself to all the things that are 
basically available in C. And limiting your project to C means that people 
don't screw that up, and also means that you get a lot of programmers that 
do actually understand low-level issues and don't screw things up with any 
idiotic "object model" crap.

So I'm sorry, but for something like git, where efficiency was a primary 
objective, the "advantages" of C++ is just a huge mistake. The fact that 
we also piss off people who cannot see that is just a big additional 
advantage.

If you want a VCS that is written in C++, go play with Monotone. Really. 
They use a "real database". They use "nice object-oriented libraries". 
They use "nice C++ abstractions". And quite frankly, as a result of all 
these design decisions that sound so appealing to some CS people, the end 
result is a horrible and unmaintainable mess.

But I'm sure you'd like it more than git.

			Linus

前两段,核心观点是 C++ 有太多不及格的程序员在使用它。
"C++ is a horrible language. It's made more horrible by the fact that a lot of substandard programmers use it."
这个我认为是没有改变的。随着 C++ 功能更加丰富,使用门槛更低,快速进行上层逻辑的抽象对接更加容易了,因此能够使用 C++ 的程序员也更多了,但能精通 C++ 各种特性做出取舍、有能力进行规范的底层设计和编程的程序员占比反而变少了。
中间段,主要在讲 C++ 会导致不好的设计,比如 STL、不灵活的对象模型等,其中又具体列举了两点:
STL/Boost 等模板库不稳定,出错时排查非常困难。这一点现在已经有了很大的改善,稳定性基本已经没问题,且现代编译器的报错已经十分友好,配合 C++17 以后的模板元编程,模板出错也没有那么难排查了。模板元编程的确可以规范很多复杂的宏元编程代码,这一点我认为是 C 值得借鉴的,但估计因为太复杂又很难加入这些特性。低效的抽象模型导致“写时一时爽,重构火葬场”。这一点和语言其实没有必然联系,而是说某些抽象模型容易导致架构僵化,并且 C++ 又容易引导人们做出这些抽象。结合上下文,Linus 主要说的应该是基于继承的对象模型。现代的设计风格已经都强调组合大于继承,像新生的 Go、Rust 语言都没有把 OOP 奉为圭臬(这两个语言恰好也是 Linus 较为欣赏的);Linux kernel 中虽然有很多对象设计,但一方面大部分是接口组合而非继承,另一方面 C 的语言层面并未支持 OOP,从而不会引导你做对象设计,所有的对象设计一定是经过谨慎取舍后最适合做对象模型的。这一点上,C++ 的 class 还是会更倾向于引导基于继承的对象设计,所以我认为 Linus 在这一观点上并不会动摇。
接下来的邮件里('Re: [RFC] Convert builin-mailinfo.c to use The Better String' - MARC),Linus 列举了两个 C 的重要优点:

On Fri, 7 Sep 2007, Linus Torvalds wrote:
> 
> The fact is, git is better than the other SCM's. And good taste (and C) is 
> one of the reasons for that.

To be very specific:
 - simple and clear core datastructures, with *very* lean and aggressive 
   code to manage them that takes the whole approach of "simplicity over 
   fancy" to the extreme.
 - a willingness to not abstract away the data structures and algorithms, 
   because those are the *whole*point* of core git. 

And if you want a fancier language, C++ is absolutely the worst one to 
choose. If you want real high-level, pick one that has true high-level 
features like garbage collection or a good system integration, rather than 
something that lacks both the sparseness and straightforwardness of C, 
*and* doesn't even have the high-level bindings to important concepts. 

IOW, C++ is in that inconvenient spot where it doesn't help make things 
simple enough to be truly usable for prototyping or simple GUI 
programming, and yet isn't the lean system programming language that C is 
that actively encourags you to use simple and direct constructs.

				Linus

1. 简单清晰的核心数据结构,配合精益激进的代码来管理,极致地实现了“简单胜于华丽”的方法。
2. 倾向于不抽象掉数据结构和算法,因为这是 git 的核心。
简单,这是用 C 最大的优点,也是 Linus 用它做底层设计最核心的原因。而 C++ 的强项正好在于复杂的抽象,并且在强化抽象能力上一骑绝尘......需求完全不匹配了可以说是。
在接下来另一封邮件('Re: [RFC] Convert builin-mailinfo.c to use The Better String' - MARC)中,Linus 对上述看法做了引申,表示“你可以用任何语言写出糟糕的代码,但是 C++ 这种带有心智包袱的语言尤其不好”。并继续说明 git 中的抽象层次很低,C++ 的抽象模型派不上用场只会添乱等等。
C++ 到现在新增了那么多特性,在 Linus 看来对于底层编程来说可能只会徒增系统设计时的选择困难症,大部分应该都属于没什么用的“心智包袱”吧。
有人可能说我跑题了,题目中讨论的是 Linux kernel 而不是 git。那在 kernel 的邮件列表中 Linus 是这么说的(Re: Compiling C++ kernel module + Makefile - Linus Torvalds):

On Tue, 20 Jan 2004, Robin Rosenberg wrote:
> 
> This is the "We've always used COBOL^H^H^H^H" argument. 

In fact, in Linux we did try C++ once already, back in 1992.

It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.

The fact is, C++ compilers are not trustworthy. They were even worse in 
1992, but some fundamental facts haven't changed:

 - the whole C++ exception handling thing is fundamentally broken. It's 
   _especially_ broken for kernels.
 - any compiler or language that likes to hide things like memory
   allocations behind your back just isn't a good choice for a kernel.
 - you can write object-oriented code (useful for filesystems etc) in C, 
   _without_ the crap that is C++.

In general, I'd say that anybody who designs his kernel modules for C++ is 
either 
 (a) looking for problems
 (b) a C++ bigot that can't see what he is writing is really just C anyway
 (c) was given an assignment in CS class to do so.

Feel free to make up (d).

		Linus

这里 Linus 讲了曾经尝试用 C++ 写 kernel 的经历,列举了三点:
C++ 异常根本用不了。编译器或语言会隐式地进行内存分配等操作,这是无法接受的。用 C 一样可以进行对象设计,并且还不用操心 C++ 的复杂特性。
放在 C++20 来看:1. 异常当然还是用不了;2. 隐式内存分配问题应该可以通过禁用内置的 new 配合自定义 allocator 来避免,但能接受这个复杂性的基础是 C++ 有其他显著优势值得引入;3. 面向对象设计的问题,之前在 git 的邮件里已经赘述很多了。
这么看起来,就算是到了 C++20,还是很难有吸引 Linus 在内核中使用 C++ 的点。
综合来看,Linus 不喜欢在项目中使用 C++ 主要集中于两点:
模板库的不稳定、难排错;C++ 的抽象能力也带来了心智包袱,在简单清晰方面不如 C。
模板现在其实已经进化得比较好用了,在某些情况下的确可以通过规范的元编程避免复杂的宏定义,这也是题目中 David Howells 提议 C++ 进内核的基础。但是,简单,才是 Linus 偏好用 C 而非 C++的核心原因。而 C++ 的复杂性,特别是在底层编程中徒增“心智包袱”的抽象能力,怕还会是它进入内核等项目最大的阻碍。
言之有理。Linux kernel里面一堆宏代码,真是令人头大。不过用C++模板,也可以搞出看不懂的魔法代码来。
另一个方向是,给C增砖添瓦,把C++的特性吸收过来。C23已经加了一些。还有很多C++里面的特性可以在不改变C语言核心的情况下加进来。而且最好在后续的发展中把C变成完全就是C++的子集。现在C与C++的兼容性还是很多问题存在。
还有Linux kernel的编译系统也过时了。不过目前没有好用的替代品。
这个回答下的很多人真是太差太差,觉得引入C++会带来很多“黑魔法”令人看不懂,殊不知Linux kernel本身的C代码才是充斥着各种各样的以宏为首的黑魔法。
这些人一半是没看过Linux里面的各种宏,一半是还用着C++11这种“modern C++”,举个例子都只能举得出来烂大街的“C++模板”,要不要去看看kernel里为了实现模板造的那套宏黑魔法?
再者,C++模板,这回答下被吐槽很多的都是些什么模板元编程的内容,再加点SFINAE吧,所以我说这里面很多人都还抱着C++11这种古代C++叫modern,迭代到C++20乃至23,C++针对元编程技术早就在可读性上进化了许多,包括SFINAE,C++20的concept都可以在很大范围内取代掉它了。
同样是要上天,C++开飞机,仪表盘一大堆旁人根本看不懂直呼高深莫测,说飞机太复杂了,还是用脚走比较“朴实无华”,然而目标是要上天,你用脚,就只能“朴实无华”地干出更复杂的事情。
C++的所谓“复杂”,是语法条例的繁琐,凭借着C++20的强大语言特性,很多需求都不需要太过堆砌令人看不懂的代码打“黑魔法”;而很多人幻想中的“C语言”是全文都是朴实无华的代码、一眼就能看透的语法,但是需求是恒定的,孱弱的“朴实无华”代表C语言代码有各种你分开看知道是在干什么、合起来就看不懂的黑魔法,这个才叫“心智负担”。
说C++ABI复杂、说写C++的人菜、说C++性能不好我都不想说什么,说C++很多黑魔法C语言朴实无华,未免有点倒反天罡。
如果是基于meta programming的这些考虑,Linux社区不如投点人力把zig建设起来,直接用zig开发了,zig对于C背景的程序员不要太友好。
这个在外网讨论得也很热烈。
其实linux使用的C也并不是C的全部特性,只是部分特性,并且也不完全是标准C,而是加上了一部分linux专用的扩展C语法,这个规范叫做“kernel C”。
意见建议引入的C++,也是有一个规范的,到时候可以叫做kernel C++,只允许使用C++的部分特性,主要是模板和强类型,像什么private/public/virtual/overload之类的功能,可能都不允许使用,如果有必要,也可以加上kernel C++专用的扩展特性,依然是交给gcc实现。
按照这个方式引入C++对linux kenel的代码不会有太多副作用,基本上就是白嫖C++的方便特性,但是能不能成估计还是得看linus。外网回答搞笑的是这个:


当年也是他喷C++,生怕C++被引入到C++内核。
现在怎么说呢,gcc都已经迁移到了C++,C++不需要靠linux来证明什么。他爱用不用。
问就是没必要,毕竟大火都是颅内展开宏,看到c代码就知道汇编
认真回答
首先,这不是“重写” 而是“拓展”,毕竟c++兼容大部分c。也并不是使用c++,而是使用某种c++方言“Kernel C++”
其次,这也不是第一次提出来,请认真阅读邮件列表,早在2018年就已经提出 ,[PATCH 08/45] C++: Implement abs() as an inline template function 带来的收益看代码一目了然
当然,最终解释权归linus所有
最后,大致浏览一下c/c++的特性对比:
核心语意
语法,c++兼容大部分c,注意是大部分,c转换到c++任然是需要修改的,比如c中的 void * 到其他指针类型的隐式转换在 c++中 是不允许的,所以要么修改代码 要么扩展编译器,有部分工作量
RAII, 核心是析构函数,c现在会有一种比较trick的方式来模仿 https://stackoverflow.com/questions/34574933/a-good-and-idiomatic-way-to-use-gcc-and-clang-attribute-cleanup-and-point , 我觉得不如抄 c++
异常,没啥说的,必ban
modules,比头文件先进太多了
TMP
TMP是提案作者的核心论点,类型安全+复用代码,想不出来为什么还要用宏。有了concept 之后,约束也变得非常简单,不在需要大部分SFINAE黑魔法。
虽然现在宏有token生成的功能,但在c++ 静态反射功能出现后也可以实现,甚至更强大(可以处理token)
长远来看,宏用的越少越好
STL
算法部分,没有不用的理由
容器部分,首先得支持freestanding(Freestanding and hosted implementations),其次要考虑性能和堆分配,大概率不用
OOP
大概率不用
多态,虽然有回答提到c里面会手写虚表,但这并不意味着可以用virtual,自动生成虚表 有个最大槽点 abi 不稳定,手写虚表加函数位置是固定的,但是加 virtual 方法不能指定虚表位置,直接 g…参考 ms 那一坨 com,C++ 工程实践(5):避免使用虚函数作为库的接口
继承,没有虚函数的继承不明白有什么不好…
封装,无所谓了
总结一下
对开发者有利,需要工具链维护者投入一定的工作量,对使用者没有任何影响。
哪怕真接受提案,估计也得好几年功夫,内核开发从邮件列表迁移到github都没搞定(
最终解释权归linus所有,观望咯
目前也有一些操作系统内核是使用C++开发的, 例如Google Fuchsia的锆石内核(Zircon), 以及SerenityOS的内核.
锆石内核使用C++17标准和C11标准, 编译器为LLVM主线. 禁用了如下C++功能
异常RTTI和dynamic_cast操作符重载虚继承静态对象初始化列表trailing return type(就是Rust用的那种auto xxx() -> yyy语法)线程局部存储标准库std
基本上所有现有的C++代码都无法在Kernel C++下使用. 这与Rust不同, Rust的很多no_std crate, 包括标准库core和alloc的一个子集都可以在Rust for Linux中使用(但是Rust for Linux不能使用cargo, 因此必须把代码复制过来)
为了使用一些纯模版代码, 内核必须实现或者移植一个精简的标准库, 也就是从stdlibc++或者libc++中复制, 或者新写. 但是libstdc++的协议为GPLv3, 显然GPLv2的Linux kernel不会使用这种协议(Linus本人反对GPLv3的anti-tivoization条款). libc++一般是和clang++一起使用的, Linux kernel又不能放弃支持GCC, 虽说理论上gcc可以和libc++一起使用, 但似乎只有一些Linux发行版编译的chromium在这么用. 如果不从现成的标准库中精简, 这个代码从何而来又是一个问题.
再考虑编译器版本问题. Linux kernel目前官方支持的编译器是GCC 5.1+或Clang 11+. 这两个编译器都完整支持C++14, 但如果想使用C++17, 则需要升级到GCC 7 (Clang 5完整支持C++17), 如果想升级到C++20, 则至少要升级到GCC 10才能支持Concepts, Clang则需要升级至16. GCC10发布于2020年, LLVM16发布于2023年. 如此剧烈的抬升最低GCC的版本, 肯定是不会接受的, 因此该提案最稳妥的方法是只将C++14引入Linux kernel. 另一方面, Rust for Linux使用了大量的unstable功能, 因此经常抬升rustc的版本, 直到所有的功能均进入stable, 但这也限制了Rust for Linux重写已有的功能.
关于ABI的问题, Linux kernel从策略上是不支持任何树外模块的, 因此所有的内核模块理论上已经使用同一个编译器编译了. 像Android的GKI内核也是要求必须使用特定的编译器编译. 因此不存在任何ABI的问题.
如果Linux kernel社区想要把C++引入内核, 最重要的部分不是先想象C++20, C++23有什么好功能, 应该先让现有的代码能用C++模式编译通过, 尤其是老的g++5.1用-std=gnu++14编译通过, 否则就像Rust For Linux一样只能开发叶模块了, 那就失去意义了. 虽说C89是C++的子集, 但Linux kernel用的充满了GNUiasm和UB的代码真不一定兼容C++. 这些老旧的GCC编译器才是C++进内核最大的阻碍.
连Rust这种1910年现割了进宫的都能写内核了。为啥C++老正白旗就不行。。。C++赶不上C语言,还赶不上你Rust这种货。。
别的都暂且不谈, 只把C++20编译期也就是模板相关的那部分引入linux kernel就挺好的, 比起到处乱飞的宏, 模板还是先进了太多.
linus估计不会同意,但有一说一,搞个c++20的子集弄个kernel c++还真不是完全不行,通过这种方式能避免一些cpp的历史包袱,有效缓解代码风格不同的问题。
主要是c++20确实香啊,等23/26稳定了估计更香,而且没有任何一个语言在与c混编这块能比得了c++。
只要不出现这些玩意儿,我举双手赞同
黑魔法模板(不是所有的模板都叫黑魔法,别混淆概念!), 如果你不理解我说的, 就想想 Boost的PFR和Describe 这俩哥们儿中西结合, 宏+模板两开花, 调试的你直挠头莫名其妙的重载,特别点名 operator =数不清的代码风格, concept 都能给你整出茴字的四种写法异常处理(最好全给禁了)语言律师(language lawyer), 评论区的一些敏锐的老兄已经发现这个问题了!
我开始担心kernel开发者 codereview 的心智负担了
风格能统一, 大家才能一起玩, 这提案才有戏
但是写C++的谁都不服谁啊!!!
先看linus怎么说工业还是得追求量产(首先有比较固定的生产流程)和品控(质量可接受,上下限差别不大,以及有可靠的检测手段)。我觉得cpp。。。,c起码花活没那么多。对了 cpp兼容性如何(前向和后向的)?
(以上当我口嗨,一来没写过内核代码,二来cpp写的还不多)
很多人以为这是一个cpp项目和另一个(潜在的)cpp项目的区别。
错了。
如果这样想那从根儿上就歪了,因为这实际上是用户态和内核态的区别。
别看cpp从98到20了,还是linus说的那个问题:cpp的代码生成比C复杂,更难一眼看出生成什么样的汇编代码,review的心智负担重。
比如栈上声明临时变量,对C来说这需要显式写一个init,提醒开发者这里有一个初始化行为,但cpp需要你自己意识到这会生成一次函数调用(构造函数)。
这样的例子还多的是,运算符重载,RVO,虚表带来的memlayout变化,拷贝构造、移动构造。。
开发效率高带来的是review负担加重。
implicit的东西太多了,而C里都是explicit,只要眼睛看到就知道生成的汇编,不用多想。
是不能用写用户态程序的思路看内核的,因为内核跟用户态那些cpp基础设施在开发模式上有本质区别。
内核调试更困难(没有随时stop world的gdb),崩溃造成的波及面大(崩进程 vs. 崩机子),而且汇编代码长什么样非常非常重要。
这意味着,开发效率要让位于可控性、稳定性。
讨论说的没错,20那些feature会让效率高,但心智负担的问题没有任何改变,这才是cpp进不了内核的本质原因,然而这个问题已经基本无解了。
C固然不足,语法过于简陋,以至于需要一堆宏来扩展语法。
但这并不是说引入C++就能解决问题的。
C++设计得比较早,那时候的语法设计理念跟现在不一样,语法设计经验较少。
那时候的理念是啥?是写得快写得爽就行,而不考虑代码可读性和防错机制,因此像隐式转换、函数重载、多继承、异常这些可读性差的还容易出错的特性层出不穷。
Linus目前的主要工作是内核code review,因此从利益相关的角度,他就不愿意在内核引入C++,开发者是写得爽了,他review代码的时候还要时刻注意某个函数调用是否抛了异常,而不能单纯从调用就看出来有没有对错误进行处理,等等。
因此即使是为了解决C语法简陋的问题,按照现代化语言的理念(尽量显式,保证安全如Null safety等)来扩展C,都比引入C++要合理得多。
建议用C++23,如吧主所言,23前取不了地址
其实C++早就比C语言更适合内核编程了,只是迫于linus的淫威都不敢提。
先不说仅仅RAII就能解决大部分内存问题,C++比起C最大的优点是性能。由于多年来一直坚持零开销抽象,在保证性能下限不低于C的情况下,C++语法已经比Java还方便了,用现代C++可以集中精力思考系统设计而不是钻研各种奇技淫巧跟简陋的语法作斗争
随便翻翻linux源码就能发现很多“偷懒”行为,比如大量使用侵入式链表(很多人鼓吹),有点基本常识都知道链表比数组慢几十倍,大神一通操作还不如小白一个vector来得简单高效,为什么不用? 还不是因为C抽象能力不足,写个动态数组还得定义移动函数。这种为了简化实现而牺牲性能的妥协随处可见,我很好奇因为固守C这门古老的语言linux到底比理想状态慢了多少
还有人扯什么C++盛产垃圾程序员,说句最真心的话我见过最恶心最低效的代码就是嵌入式,尤其MCU,用了linux C++的水平已经高了不少
顺便说一下,国内嵌入式跟国外是两个行业,德国最新的机床普遍基于C++20,在没有操作系统、不允许堆分配的极端场景依然工作良好,国内则普遍认为嵌入式只能用C,人家用协程,你对着状态表手写状态机,同等智商下当然别人更快,更可靠,中、德机床技术差距就是C++普及度差距。
有趣的视频,国外小哥演示在8位CPU使用C++17
是转化为标准C++编译器可以编译的代码吧,让其成为标准C++子集。这个工作在GCC,libc等库上已经完成了,转化为标准C++应该主要还是测试工作。
支持一个这样的子集。c确实封装性太差了。原本编译器很优雅的解决的问题,让程序员搞的指针满天飞。头发都少了不少。
其实cpp的问题是因为太强大而没有约束的使用。语法特性多不是坏事,或者说好的语法设计一定是为了更方便的解决问题的,把实现在语言层面解决,让编译器做脏活。
任何语言都一样,没有了约束,都会屎山。
写C习惯了,得心应手,不想换语言,有人也是这样想的吗
[收藏本文] 【下载本文】
   科技知识 最新文章
《消失的问界里》为什么网传华为选择大面积
特斯拉万人大裁员涉及中国市场,销售部门是
媒体报道「特斯拉一天内失去 2 个高管和 10
去年是「大模型元年」,今年会是「AI应用落
2024 年人工智能方向的就业前景怎么样?
如何评价小米汽车SU7全球首例无故抛锚?
如何评价比亚迪与大疆合作发布的车载无人机
如何看待波音「吹哨人」遗言曝光:如果我出
电动汽车为什么一下爆发了?
怎么看待华为太空宽带计划?
上一篇文章      下一篇文章      查看所有文章
加:2024-01-15 23:48:28  更:2024-01-16 10:03:50 
 
 
股票涨跌实时统计 涨停板选股 分时图选股 跌停板选股 K线图选股 成交量选股 均线选股 趋势线选股 筹码理论 波浪理论 缠论 MACD指标 KDJ指标 BOLL指标 RSI指标 炒股基础知识 炒股故事
网站联系: qq:121756557 email:121756557@qq.com  天天财汇