您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C 不再是一种编程语言

时间:2022-03-25 09:18:32  来源:  作者:CSDN程序人生

近日,Rust和Swift资深专家Aria Beingessner发布的一篇文章《C 不再是一种编程语言》在Hacker News上引起了热烈讨论。

原文链接:
https://gankra.Github.io/blah/c-isnt-a-language/

Hacker News评论区:

https://news.ycombinator.com/item?id=30704642

Aria和朋友Phantomderp在“对C ABI接口感到非常失望并试图修复上”达成了高度一致。

但在失望的原因上,Aria与朋友各自持不同意见。那具体产生了哪些分歧呢?为什么会提出C不再是一种编程语言的观点呢?笔者对原文进行了编译:

整理 | 于轩

出品 | 程序人生 (ID:coder _life)

Phantomderp试图从原生上改善使用C本身作为编程语言的条件,而Aria则希望改善使用C以外的任何语言条件。

这时候大家就会产生疑问了,这个问题和C有什么关系?

Aria表示:如果C真的是一种编程语言,那就和它无关。不幸的是,它并不是。这不是说数十亿种实现方式和失败的层次结构,导致它的定义方式非常糟糕的事实,而是C被提升到一个具有威望和权力的角色,它的统治是绝对和永恒的。C是编程的通用语言,我们都必须学C,因此C不再只是一种编程语言,它成了每一种通用编程语言都需要遵守的协议。

这实际有点像是关于整个“C是一个不可捉摸的实现定义混乱” 。但仅因为它让我们不得不使用这个协议,这就变成了一个更大的噩梦。

C 不再是一种编程语言

外部功能接口

下面一起来谈谈技术问题。假如你已经完成了你的新语言BAppyscript的设计,对Bappy Paws/Hooves/Fins有一流的支持。这是一种神奇的语言,将彻底改变cats、sheep、和sharks的编程方式。

但现在需要让它真正做一些有用的事情。比如接受用户的输入,或者输出,或者字面上的任何可观察之类的东西。如果你想让该语言编写的程序与主流操作系统兼容,那就需要与操作系统的界面进行交互。听说linux上的一切都“只是一个文件”,所以一起在Linux上打开一个文件吧!

OPEN(2)
NAME open, openat, creat - open and possibly create a file
SYNOPSIS
 #include <fcntl.h>
 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
 int creat(const char *pathname, mode_t mode);
 int openat(int dirfd, const char *pathname, int flags); int openat(int dirfd, const char *pathname, int flags, mode_t mode); /* Documented separately, in openat2(2): */ int openat2(int dirfd, const char *pathname, const struct open_how *how, size_t size);
 Feature Test macro Requirements for glibc (see feature_test_macros(7)):
 openat: Since glibc 2.10: _POSIX_C_SOURCE >= 200809L Before glibc 2.10: _ATFILE_SOURCE

这是Bappyscript,不是C,那Linux的Bappyscript接口在哪里?

你说Linux中没有Bappyscript接口是什么意思?好吧,当然是因为这是一种全新的语言,但你会添加一个,对吗?那这时你就会发现,你好像必须使用他们给的东西。

你将需要某种接口,让语言能够调用外部的函数,就像外部函数接口FFI。然后你发现Rust也有C FFI,Swift也有,甚至Python/ target=_blank class=infotextkey>Python也有。

C 不再是一种编程语言

你会发现,每个人都必须学会C才能与主流的操作系统对话,然后当需要相互对话时,大家突然都用起了C。所以…为什么不直接用C来相互对话呢?

现在C就变成了一种编程通用语言,不仅是一种编程语言,它还是一种协议了。

C 不再是一种编程语言

与C对话包括哪些内容?

很明显,基本上每种语言都必须学会与C进行对话,而且这种语言绝对是非常明确的。

"对话 "C是什么意思?它意味着以C头文件的形式获得接口类型和功能的描述,并以某种方式:

  • 匹配这些类型的布局

  • 用链接器做一些事情,将函数的符号解析为指针

  • 用适当的ABI来调用这些函数(比如把args放在正确的寄存器中)

那么,这里就有几个问题:

  • 你实际上不能写一个C解析器

  • C实际上没有ABI,甚至没有定义的类型布局

C 不再是一种编程语言

实际上无法解析一个C头文件

Aria曾断言解析C基本上是不可能的,但有人说其实有很多工具可以读取C头文件,比如rust-bindgen。事实果真如此吗?其实不然。

bindgen使用libclang来解析C和C++头文件。要修改bindgen搜索libclang的方式,请参阅clang-sys文档。关于bindgen如何使用libclang的更多细节,请参阅bindgen用户指南。

任何花费大量时间试图快速解析C(++)头文件的人都会很快放弃,然后让一个C(++)编译器来做这件事。请记住,有意义地解析C头文件不仅仅是解析:你还需要解决#includes、typedefs和macros的问题!所以现在不仅要实现所有相关功能,还要实现所有平台的头文件解析逻辑,并且还需要想方设法找到DEFINED!

就拿Swift来说,它在C互操作和资源方面拥有绝对优势,它是由苹果开发的一门编程语言,有效取代了Objective-C,成为在其平台上定义和使用系统API的主要语言。在这样做的过程中,它比其他任何人都更进一步实现了ABI稳定性和设计概念。

它也是Aria见过的最支持FFI的语言之一。它可以本地导入(Objective-)C(++)头文件,并产生一个漂亮的本地Swift接口,其类型在边界自动 "桥接 "到它们的Swift对等项(由于类型具有相同的ABI,所以通常是透明的)。

Swift也是由苹果公司中许多构建和维护Clang和LLVM的人开发。这些人都是C及其衍生品方面的世界顶级专家。Doug Gregor就是其中之一,他曾表达了对C FFI的看法:

C 不再是一种编程语言

所有这些都是Swift内部使用Clang来处理 C(++) ABI的原因。这样一来,我们就不会去追着Clang增加的每一个影响ABI的新属性。

可以看出,即使是Swift也不想花时间解析C(++)头文件。那么,如果你绝对不想让C编译器在编译时解析和解决头文件,你该怎么做呢?

你需要手工翻译!int64_t? 还是写i64. long…?什么是long?

C 不再是一种编程语言

C实际上没有ABI

好吧,这没有什么好惊讶的:C语言中的整数类型,为了 “可移植性”而被设计成摇摆不定的大小,实际上大小也是不稳定的。我们可以认为CHAR_BIT很奇怪,但这也不能帮助我们了解long的大小和对齐方式。

有人说每个平台都有标准化的调用约定和ABI,确实有,而且它们通常定义了C中关键原语的布局(并且有些不只是用C类型来定义调用约定,这里侧眼于AMD64 SysV)。

还有一个棘手的问题:架构并没有定义ABI,操作系统也是。我们必须在一个特定的目标三元组上全力以赴,比如 “x86_64-pc-windows-gnu”(不要和 "x86_64-pc-windows-msvc "混淆)。经过测试,一共有176个三元组。

> rustc --print target-list
aarch64-apple-darwinaarch64-apple-IOSaarch64-apple-ios-macabiaarch64-apple-ios-simaarch64-apple-tvos
...armv7-unknown-linux-musleabiarmv7-unknown-linux-musleabihfarmv7-unknown-linux-uclibceabihf...x86_64-uwp-windows-gnux86_64-uwp-windows-msvcx86_64-wrs-vxworks>_

这实在是有太多ABI了,因为测试中甚至没有用到所有不同的调用约定,如stdcall vs fastcall或aapcs vs aapcs-vfp。

但至少所有这些ABI和调用约定之类的东西,都可以一种方便使用的机器可读格式获得。至少主流的C编译器在特定目标三元组的ABI上达成了一致! 当然有一些奇怪的jank C编译器,但Clang和GCC不是:

> abi-checker --tests ui128 --pAIrs clang_calls_gcc gcc_calls_clang
...
Test ui128::c::clang_calls_gcc::i128_val_in_0_perturbed_small passedTest ui128::c::clang_calls_gcc::i128_val_in_1_perturbed_small passedTest ui128::c::clang_calls_gcc::i128_val_in_2_perturbed_small passedTest ui128::c::clang_calls_gcc::i128_val_in_3_perturbed_small passedTest ui128::c::clang_calls_gcc::i128_val_in_0_perturbed_big failed!test 57 arg3 field 0 mismatchcaller: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]callee: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]Test ui128::c::clang_calls_gcc::i128_val_in_1_perturbed_big failed!test 58 arg3 field 0 mismatchcaller: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]callee: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]
...
392 passed, 60 failed, 0 completely failed, 8 skipped

上面是Aria在Ubuntu 20.04 x64上运行的FFI abi-checker,她在这个相当重要的、表现良好的平台上测试了一些非常无聊的情况。结果发现,一些整数参数在两个由Clang和GCC编译的静态库之间按值传递失败了!

Aria发现,Clang和GCC甚至不能就Linux x64上_int128的ABI达成一致。

Aria本来是为了检查rustc中的错误,没想到会在一个重要的、常用的ABI上发现两大主流C编译器的不一致。

C 不再是一种编程语言

试图驯服C

Aria认为,可怕的是对C头文件进行语义解析,只能由该平台的C编译器来完成。即使C编译器告诉了你类型和如何理解注释,但实际上你仍然不知道所有内容的大小/对齐/惯例。那如何与这些乱七八糟的东西进行互操作呢?Aria提供了两种选择。

第一个选择是完全投降,将你的语言与C进行灵魂绑定,这可以是以下任何一种:

  • 用C(++)编写你的编译器/运行时,这样它就可以用C了

  • 让你的 "codegen "直接发出C(++),这样用户无论如何都需要一个C编译器

  • 将你的编译器建立在一个成熟的主要C编译器(Clang或GCC)之上

但上面这些也只能让你走这么远,因为除非你的语言真的暴露了unsigned long long,否则你将继承C的巨大可移植性混乱。

这就让我们想到了第二个选择:撒谎、欺骗和偷窃。

如果这一切是无论如何都无法避免的灾难,你还不如开始手工翻译类型和接口定义到你的语言中,基本上就是我们每天在Rust中所做的事情。比如,人们使用rust-bindgen和friends自动化处理一些事,但很多时候,定义会被检查或手工调整。因为人们不想浪费时间,去尝试Phantomderp的定制C构建系统可移植地工作。

在Rust中,Linux x64上的intmax_t是什么?

pub type intmax_t = i64;

在Nim中,Linux x64上的long long是什么?

clonglong {.importc: "long long", nodecl.} = int64

很多代码已经完全放弃将C保持在循环中,开始对核心类型的定义进行硬编码。毕竟,它们显然只是平台ABI的一部分!他们要改变intmax_t的大小吗?这显然是一个破坏ABI的变化!

那phantomderp正在研究的又是什么?

我们讨论过为何intmax_t不能被改变,因为如果我们从long long(64位整数)改为_int128_t(128位整数),某个地方的二进制会失控使用错误的调用约定/返回约定。但有没有一种方法,如果代码选择了它或其他东西,我们可以为较新的应用程序升级函数调用,而让旧应用程序保持不变?让我们编写一些代码,测试一下透明别名可以帮助ABI的想法。

Aria提出了她的疑问:编程语言如何处理这种变化?如何指定与哪个版本的 intmax_t互操作?如果你有一些C头文件提到intmax_t,它使用的是哪个定义?

在此讨论具有不同ABI的平台的主要机制是目标三元组。你知道什么是目标三元组吗?你知道基本上涵盖了过去20年里所有主流桌面/服务器Linux发行版的 x86_64-unknown-linux-gnu包括什么吗?现在,虽然表面上可以针对这个目标进行编译,并得到一个在所有这些平台上都能“正常工作”的二进制文件,但Aria不相信有些程序会被编译成intmax_t大于int64_t

任何试图做出这种改变的平台都会成为一个新的x86_64-unknown-linux-gnu2 目标三元组吗?如果任何针对x86_64-unknown-linux-gnu编译的东西都被允许在上面运行,这难道还不够吗?

C 不再是一种编程语言

 

在不破坏ABI的情况下更改签名

"那又怎样,C永远不会再有进步吗?"不!但也是!因为他们提供了糟糕的设计。

老实说,进行ABI兼容的修改是一种艺术形式。这种艺术的一部分就是准备工作。具体来说,如果你准备好了,做出不破坏ABI的修改就会容易得多。

正如phantomderp的文章所指出的,像glibc( g  x86_64-unknown-linux-gnu 中的 gnu )早就明白了这一点,并使用符号版本化这样的机制来更新签名和API,同时为任何针对旧版本编译的人保留旧版本。

因此,如果你有 int32_t my_rad_symbol(int32_t) ,你告诉编译器将其导出为 my_rad_symbol_v1 ,那么任何根据这个头文件进行编译的人,都会在他们的代码中写上 my_rad_symbol ,但针对 my_rad_symbol_v1 链接。

然后当你决定实际上应该使用int64_t时,你可以把int64_t my_rad_symbol(int64_t) 作为my_rad_symbol_v2,但保留旧的定义作为my_rad_symbol_v1。任何针对较新版本头文件进行编译的人都会高兴地使用v2符号,而针对旧版本进行编译的人则继续使用v1!

但是你仍然有一个兼容性的问题:任何用新头文件编译的人都不能与库的旧版本进行链接,库的V1版本根本没有V2符号!因此,如果你想获得热门的新功能,你就要接受与旧系统的不兼容。

不过这并不是什么大问题,它只是让平台供应商感到难过,因为没有人能够立即使用他们花了这么多时间做的东西。你不得不推出一个闪亮的新功能,然后让大家等待它变得足够普遍和成熟。但为了人们愿意依赖它并中断对旧平台的支持(或者愿意为它实施动态检查和回退)时,你必须坐等几年。

如果你真的想让人们立即升级,那就要谈论向前兼容的问题。这让旧版本的东西以某种方式与他们没有概念的新功能一起工作。

C 不再是一种编程语言

在不破坏ABI的情况下更改类型

那除了可以改变一个函数的签名,还可以改变类型布局吗?Aria表示,这取决于你是如何暴露类型的。

C真正奇妙的一个特点是,它可以让你区分一个已知布局的类型和一个未知布局的类型。如果你只在C头文件中前向声明一个类型,那么任何与之交互的用户代码都不被“允许”知道该类型的布局,并且必须一直在指针后面不透明地处理它。

所以你可以做一个像MyRadType* make_valuse_val(MyRadType*)的API,然后使用同样的符号版本技巧来暴露make_val_v1 use_val_v1符号,任何时候你想改变这个布局,你就在所有与该类型交互的东西上增加版本。类似地,你在MyRadTypeV1MyRadTypeV2和一些类型定义中保留了一些,以确保人们使用“正确”的类型。这样就可以在不同的版本之间改变类型的布局。

如果多个东西建立在你的库之上,然后开始用不透明类型相互交谈,坏事就会发生:

  • lib1: 制作一个API,接受MyRadType*并调用use_val

  • lib2:调用 make_val并将结果传递给lib1

如果lib1和lib2针对库的不同版本进行了编译,那么make_val_v1就会被输入到use_val_v2中!你有两个选择来处理这个问题:

1.说这是被禁止的,责备那些无论如何都要这么做的人,然后伤心

2.以一种向前兼容的方式设计MyRadType,这样混合就可以了

常见的前向兼容技巧包括:

  • 保留未使用的字段供未来版本使用

  • MyRadType的所有版本都有一个共同的前缀,可以让你“检查”你所使用的版本

  • 拥有自定大小的字段,以便旧版本可以“跳过”新的部分

C 不再是一种编程语言

 

案例研究:MINIDUMP_HANDLE_DATA

微软是这种向前兼容的大师,甚至可以实现在架构之间保持布局兼容。Aria最近正在处理的一个例子是Minidumpapiset.h中的
MINIDUMP_HANDLE_DATA_STREAM。

这个API描述了一个有版本的值列表。该列表以这种类型开始:

typedef struct _MINIDUMP_HANDLE_DATA_STREAM { ULONG32 SizeOfHeader; ULONG32 SizeOfDescriptor; ULONG32 NumberOfDescriptors; ULONG32 Reserved;} MINIDUMP_HANDLE_DATA_STREAM, *PMINIDUMP_HANDLE_DATA_STREAM;

其中:

  • SizeOfHeader
    MINIDUMP_HANDLE_DATA_STREAM本身的大小。如果他们需要在最后增加更多的字段,那也没关系,因为旧版本可以使用这个值来检测头的“版本”,也可以跳过任何他们不知道的字段。

  • SizeOfDescriptor是数组中每个元素的大小。这让你知道你有什么 "版本 "的元素,并跳过任何你不知道的字段。

  • NumberOfDescriptors是数组长度

  • Reserved是一些额外的内存,无论如何他们决定保留在头文件中(Minidumpapiset.h非常谨慎,从不在任何地方进行填充,因为填充字节有未指定的值,而且它是一种序列化的二进制文件格式。我希望他们添加这个字段是为了使结构的大小是8的倍数,这样就不会有任何关于数组元素在标题之后是否需要填充的问题。这是在认真对待兼容性!)

而事实上,微软实际上有理由使用这种版本方案,并定义了两个版本的数组元素:

typedef struct _MINIDUMP_HANDLE_DESCRIPTOR { ULONG64 Handle; RVA TypeNameRva; RVA ObjectNameRva; ULONG32 Attributes; ULONG32 GrantedAccess; ULONG32 HandleCount; ULONG32 PointerCount;} MINIDUMP_HANDLE_DESCRIPTOR, *PMINIDUMP_HANDLE_DESCRIPTOR;
typedef struct _MINIDUMP_HANDLE_DESCRIPTOR_2 { ULONG64 Handle; RVA TypeNameRva; RVA ObjectNameRva; ULONG32 Attributes; ULONG32 GrantedAccess; ULONG32 HandleCount; ULONG32 PointerCount; RVA ObjectInfoRva; ULONG32 Reserved0;} MINIDUMP_HANDLE_DESCRIPTOR_2, *PMINIDUMP_HANDLE_DESCRIPTOR_2;
// The latest MINIDUMP_HANDLE_DESCRIPTOR definition.typedef MINIDUMP_HANDLE_DESCRIPTOR_2 MINIDUMP_HANDLE_DESCRIPTOR_N;typedef MINIDUMP_HANDLE_DESCRIPTOR_N *PMINIDUMP_HANDLE_DESCRIPTOR_N;

这些结构的实际细节不是很有趣,除了:

  • 他们只是通过在末尾添加字段来改变它

  • 有一个“最新版本”的类型定义

  • 保留了一些也许再次Padding(填充)(RVA是一个ULONG32)

这是一个坚不可摧的向前兼容的庞然大物。它们对填充非常小心,它甚至在32位和64位之间有相同的布局 (这实际上是非常重要的,因为你希望一个架构上的minidump处理器能够处理来自每个架构的minidump)。

C 不再是一种编程语言

案例研究:jmp_buf

Aria对这种情况不是很熟悉,但在研究历史上的glibc中断时,她在LWN上看到了一篇很棒的文章:《glibc s390 ABI中断》,她假设它是准确的。

事实证明,glibc曾经破解过类型的ABI,至少在s390上。根据这篇文章的描述,它是混乱的。

特别是他们改变了setjmp/longjmp使用的保存状态类型的布局,即jmp_buf。现在,他们知道这是一个破坏ABI的变化,所以他们做了负责任的符号版本化的事情。

jmp_buf并不是一个不透明的类型,其他东西都在内联地存储这个类型的实例,比如Perl的运行时间。不用说,这个相对晦涩的类型已经渗透到许多二进制文件中去了,最终的结论是,Debian的所有东西都需要重新编译!

这篇文章甚至讨论了将libc版本升级以应对这种情况的可能性:

在像debian这样的混合ABI环境中,SO名称碰撞导致两个libc被加载并争夺相同的符号命名空间,而解析(以及因此选择ABI)则由ELF插值和范围规则决定。这真是一场噩梦。这可能是一个比告诉大家重建并继续生活更糟糕的解决方案。

C 不再是一种编程语言

真的能改变intmax_t吗?

在Aria看来,不完全是。就像jmp_buf一样,它不是一个不透明的类型,这意味着它被内联到大量的随机结构中,被认为具有大量其他语言和编译器的特定表示,并且可能是大量公共接口的一部分。而这些接口并不在libc、Linux,甚至不在发行版维护者的控制之下。

当然,libc可以适当地使用符号版本技巧来使其API与新的定义兼容,但改变像 intmax_t这样的基本数据类型的大小,是在一个平台的大生态系统中寻求混乱。

Aria希望被证明自己是错误的,但据她所知,做出这样的改变需要一个新的目标三元组,并且不允许任何为旧ABI构建的二进制/库在这个新三元组上运行。当然有人可以做这些工作,但Aria并不羡慕任何这样做的发行版。

即使如此,面临的还有x64的int问题:这是一个非常基本的类型,而且长期以来一直是这种大小,无数的应用程序可能对它有奇怪的无法察觉的假设。这就是为什么int在x64上是32位的,尽管它应该是64位的:int是32位的时间太长了,以至于完全无望将软件更新到新的大小,尽管它是一个全新的架构和目标三元组。

Aria再次希望自己是错的,但是人们有时犯的错误如此严重,以至于根本无法挽回。如果C语言是一种独立的编程语言?当然可以去做。但它不是,它是一个协议,还是我们必须使用的糟糕的协议。

就算C征服了世界,但也许它再也得不到好东西了。



Tags:编程语言   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Rust编程语言的内存安全与性能:如何平衡?
Rust编程语言自诞生以来,就以其独特的内存安全特性和高性能而备受瞩目。然而,如何在保证内存安全的同时,实现高效的性能,一直是Rust开发者们面临的挑战。本文将深入探讨Rust的内...【详细内容】
2024-04-12  Search: 编程语言  点击:(9)  评论:(0)  加入收藏
主流编程语言哪个更容易学?
主流编程语言哪个更容易学?在当今数字化时代,编程语言已成为一项重要的技能,越来越多的人开始学习编程。然而,对于初学者来说,选择一门容易入门的编程语言是至关重要的。在本文中...【详细内容】
2024-01-31  Search: 编程语言  点击:(148)  评论:(0)  加入收藏
用于人工智能开发的主流编程语言都有哪些?
在人工智能开发领域,编程语言的选择至关重要。目前,主流的编程语言主要包括Python、Java、C++、JavaScript和Swift等。这些语言各具特色,适用于不同的人工智能开发场景。首先,Py...【详细内容】
2024-01-31  Search: 编程语言  点击:(138)  评论:(0)  加入收藏
选择适合微服务的编程语言,让你的工作事半功倍!
讨论编程语言就像是一场政治辩论。每个开发者都会过分捍卫他/她所使用的编程语言。然而,编程语言应该被看作是它们真正是的东西,即一种工作工具。每种编程语言都有特定的目的...【详细内容】
2023-12-14  Search: 编程语言  点击:(180)  评论:(0)  加入收藏
编程语言大比拼:Python、Java、C、C++、Go 实现 'Hello World' 和九九乘法表"
应该90%的IT专业的朋友写的第一段代码就是打印"holle world",每个大学老师都会通过这个方式吸引你对课程产生兴趣。也许有的朋友学的是JAVA开发,有的学的是c,在几年前应该很...【详细内容】
2023-12-11  Search: 编程语言  点击:(219)  评论:(0)  加入收藏
谷歌AI大模型Gemini亮相:擅长复杂学科推理,能懂编程语言PK GPT-4
美国科技巨头谷歌今日宣布推出人工智能模型Gemini,并针对三种不同的尺寸优化了 Gemini 1.0:Gemini Ultra&mdash;&mdash;谷歌最大、最有能力的模型,适用于高度复杂的任务。Gemin...【详细内容】
2023-12-08  Search: 编程语言  点击:(151)  评论:(0)  加入收藏
面向AI开发的六种最重要的编程语言
作者丨FATIH K&Uuml;&Ccedil;&Uuml;KKARAKURT 译者 | 布加迪审校 | 重楼出品 | 51CTO技术栈(微信号:blog51cto)在AI开发界,你使用的编程语言很重要。每种语言有其独特...【详细内容】
2023-12-07  Search: 编程语言  点击:(122)  评论:(0)  加入收藏
Python是什么样的编程语言?有哪些特点?
Python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其...【详细内容】
2023-11-25  Search: 编程语言  点击:(228)  评论:(0)  加入收藏
一文了解低级和高级编程语言
中文是一种尽量用简短文字表达更多含义的语言,所以很多时候一句话的含义很容易曲解成别的意思。最近,有人提出C语言是一种中级语言的概念,所以特意介绍一下低级语言和高级语言...【详细内容】
2023-11-23  Search: 编程语言  点击:(232)  评论:(0)  加入收藏
AI 编程语言 Mojo 登陆 Mac 平台
10 月 20 日消息,Mojo 编程语言近日登陆 Mac 平台,为 AI 开发人员带来类似于 Python 的编程体验。Mojo 编程语言的开发工作由 Chris Lattner 领导,他同时也是苹果 Swift 编程语...【详细内容】
2023-11-20  Search: 编程语言  点击:(142)  评论:(0)  加入收藏
▌简易百科推荐
C++中的外部模板及其在当前编译文件中的实例化
在C++中,模板是一种泛型编程的工具,它允许程序员以一种类型无关的方式编写代码。然而,模板的一个常见问题是它们会导致编译时间增加,特别是在大型项目中,当多个源文件包含相同的...【详细内容】
2024-04-11  鲨鱼编程  微信公众号  Tags:C++   点击:(9)  评论:(0)  加入收藏
C++常见避坑指南
C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结,希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略。...【详细内容】
2024-04-03  腾讯技术工程    Tags:C++   点击:(8)  评论:(0)  加入收藏
C++ 之父反驳白宫警告:自诞生第一天起,C++ 的目标就一直是提高安全性
整理 | 郑丽媛上个月,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的 19 页 PDF 报告中,呼吁开发人员停止使用容易出现内存安全漏洞的编程语...【详细内容】
2024-03-25    CSDN  Tags:C++   点击:(7)  评论:(0)  加入收藏
八个 C++ 开源项目,帮助初学者进阶成长
通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。1.ThreadPool一个简单的 C++1...【详细内容】
2024-03-22  AI让生活更美好  微信公众号  Tags:C++   点击:(27)  评论:(0)  加入收藏
C# 中15个值得收藏的开源项目推荐
在开源的世界里,C# 编程语言也占有一席之地。这些开源项目涵盖了多个领域,从框架、库到工具,它们为C#开发者提供了丰富的资源和工具,帮助他们更高效地开发、测试和部署应用程序...【详细内容】
2024-03-20  程序员编程日记  微信公众号  Tags:C#   点击:(33)  评论:(0)  加入收藏
C#异步编程:Task.Run vs. async-await,掌握基础与高级用法
概述:C#中的异步编程有两主要方式:Task.Run用于在后台线程执行同步操作,而async-await更适用于清晰表达异步流程。基础用法展示了它们的简单应用,高级用法则演示了它们的结合使...【详细内容】
2024-03-09  架构师老卢  今日头条  Tags:C#   点击:(33)  评论:(0)  加入收藏
C++多线程编程:解锁性能与并发的奥秘
今天我们将深入探讨C++中的多线程编程,揭示多线程如何解锁性能潜力,提高程序的并发性能。什么是多线程?在计算机科学中,多线程是指一个进程(程序的执行实例)中的多个线程同时执行...【详细内容】
2024-02-03     AI让生活更美好  Tags:C++   点击:(74)  评论:(0)  加入收藏
C++代码优化攻略
今天我们将深入探讨C++性能优化的世界。在当今软件开发的浪潮中,高性能的代码是必不可少的。无论是开发桌面应用、移动应用,还是嵌入式系统,性能都是关键。1. 选择合适的数据结...【详细内容】
2024-01-26  AI让生活更美好  微信公众号  Tags:C++   点击:(124)  评论:(0)  加入收藏
C# 线程本地存储为什么线程间值不一样
为什么用 ThreadStatic 标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类...【详细内容】
2024-01-26  一线码农聊技术  微信公众号  Tags:C#   点击:(76)  评论:(0)  加入收藏
C++质数检测器的设计与实现​
质数,作为数学中的一个基本概念,一直以其独特的性质吸引着众多研究者和爱好者。质数是指大于1的自然数中,除了1和它本身以外不再有其他因数的数。在实际应用中,质数检测也扮演着...【详细内容】
2024-01-15  鲨鱼编程  微信公众号  Tags:C++   点击:(123)  评论:(0)  加入收藏
站内最新
站内热门
站内头条