语言是如何扩展自己的?

时间:2021-07-19 13:29:40

I am learning C++ and I've just started learning about some of Qt's capabilities to code GUI programs. I asked myself the following question:

我正在学习c++,并且刚刚开始学习Qt编写GUI程序的一些功能。我问自己以下问题:

How does C++, which previously had no syntax capable of asking the OS for a window or a way to communicate through networks (with APIs which I don't completely understand either, I admit) suddenly get such capabilities through libraries written in C++ themselves? It all seems terribly circular to me. What C++ instructions could you possibly come up with in those libraries?

c++之前没有任何语法可以向操作系统请求窗口或通过网络(我承认,我也不完全理解api)进行通信的功能,它是如何通过使用c++编写的库突然获得这些功能的呢?这一切在我看来都是非常循环的。在这些库中,您能想到什么c++指令呢?

I realize this question might seem trivial to an experienced software developer but I've been researching for hours without finding any direct response. It's gotten to the point where I can't follow the tutorial about Qt because the existence of libraries is incomprehensible to me.

我意识到这个问题对于一个有经验的软件开发人员来说可能是微不足道的,但是我已经研究了好几个小时却没有找到任何直接的回应。它已经到了我无法跟上关于Qt的教程的地步,因为我无法理解库的存在。

15 个解决方案

#1


187  

A computer is like an onion, it has many many layers, from the inner core of pure hardware to the outermost application layer. Each layer exposes parts of itself to the next outer layer, so that the outer layer may use some of the inner layers functionality.

计算机就像一个洋葱,它有许多层,从纯硬件的核心到最外层的应用层。每个层将自己的部分暴露给下一个外层,以便外层可以使用一些内部层的功能。

In the case of e.g. Windows the operating system exposes the so-called WIN32 API for applications running on Windows. The Qt library uses that API to provide applications using Qt to its own API. You use Qt, Qt uses WIN32, WIN32 uses lower levels of the Windows operating system, and so on until it's electrical signals in the hardware.

例如,Windows操作系统为运行在Windows上的应用程序公开了所谓的WIN32 API。Qt库使用该API为自己的API提供使用Qt的应用程序。你使用Qt, Qt使用WIN32, WIN32使用Windows操作系统的较低级别,等等,直到它成为硬件中的电子信号。

#2


59  

You're right that in general, libraries cannot make anything possible that isn't already possible.

您是对的,一般来说,库不能使任何不可能的事情成为可能。

But the libraries don't have to be written in C++ in order to be usable by a C++ program. Even if they are written in C++, they may internally use other libraries not written in C++. So the fact that C++ didn't provide any way to do it doesn't prevent it from being added, so long as there is some way to do it outside of C++.

但是这些库并不一定要用c++编写才能被c++程序使用。即使它们是用c++编写的,它们也可能在内部使用其他非用c++编写的库。因此,事实上c++没有提供任何实现它的方法,这并不能阻止它被添加,只要有某种方法可以在c++之外实现它。

At a quite low level, some functions called by C++ (or by C) will be written in assembly, and the assembly contains the required instructions to do whatever isn't possible (or isn't easy) in C++, for example to call a system function. At that point, that system call can do anything your computer is capable of, simply because there's nothing stopping it.

在相当低的级别上,c++(或C)调用的一些函数将在程序集中编写,并且程序集中包含了在c++中做任何不可能(或不容易)的操作所需的指令,例如调用系统函数。此时,系统调用可以做任何您的计算机能够做的事情,仅仅是因为没有任何东西阻止它。

#3


42  

C and C++ have 2 properties that allow all this extensibility that the OP is talking about.

C和c++有两个属性允许OP所讨论的所有可扩展性。

  1. C and C++ can access memory
  2. C和c++可以访问内存
  3. C and C++ can call assembly code for instructions not in the C or C++ language.
  4. C和c++可以调用汇编代码来获取不使用C或c++语言的指令。

In the kernel or in a basic non-protected mode platform, peripherals like the serial port or disk drive are mapped into memory map in the same way as RAM is. Memory is a series of switches and flipping the switches of the peripheral gets you serial port or disk drive to do useful things.

在内核或基本的非保护模式平台中,诸如串口或磁盘驱动器之类的外围设备被映射到内存映射中,其方式与RAM相同。内存是一系列的开关,打开外围设备的开关,让你的串口或磁盘驱动器做一些有用的事情。

In a protected mode operating system, when one wants to access the kernel from userspace (say when writing to the file system or to draw a pixel on the screen) one needs to make a system call. C has not instruction to make a system call but C can call assembler code that can trigger the correct system call which allows one's C code to talk to the kernel.

在受保护模式操作系统中,当您希望从userspace访问内核(比如在写入文件系统或在屏幕上绘制像素时)时,需要进行系统调用。C没有进行系统调用的指令,但是C可以调用可以触发正确的系统调用的汇编代码,从而允许C代码与内核对话。

In order to make programming a particular platform easier, system calls are wrapped in more complex functions what may perform some useful function within one's own program. One is free to call the system calls directly (using assembler) but it is probably easier to just make use of one of the wrapper functions that the platform supplies.

为了使编程变得更容易,系统调用被封装在更复杂的函数中,这些函数可以在自己的程序中执行一些有用的功能。可以直接调用系统调用(使用汇编程序),但是仅仅使用平台提供的一个包装函数可能更容易。

There is another level of API that are a lot more useful than a system call. Take for example malloc. Not only will this call the system to obtain large blocks of memory but will manage this memory by doing all the book keeping on what is take place.

还有一种API比系统调用更有用。例如malloc。这不仅会调用系统来获取大块的内存,而且还会通过保存正在发生的事情来管理这些内存。

Win32 APIs wrap some graphic functionality with a common platform widget set. Qt takes this a bit further by wrapping the Win32 (or X Windows) API in a cross platform way.

Win32 API使用通用平台小部件集包装一些图形功能。

Fundamentally though a C compiler turns C code into machine code and since the computer is designed to use machine code, you should expect C to be able to accomplish the lions share or what a computer can do. All that the wrapper libraries do is do the heavy lifting for you so that you don't have to.

虽然C编译器将C代码转换为机器码,而且由于计算机是用来使用机器码的,因此您应该期望C能够完成lions share或计算机可以做什么。包装库所做的就是为您完成繁重的工作,这样您就不必这样做了。

#4


22  

Languages (like C++11) are specifications, on paper, usually written in English. Look inside the latest C++11 draft (or buy the costly final spec from your ISO vendor).

语言(如c++ 11)是书面的规范,通常用英语编写。查看最新的c++ 11草案(或从您的ISO供应商购买昂贵的最终规范)。

You generally use a computer with some language implementation (You could in principle run a C++ program without any computer, e.g. using a bunch of human slaves interpreting it; that would be unethical and inefficient)

你通常使用一种语言实现的计算机(你可以在原则上运行一个没有任何计算机的c++程序,例如使用一群人来解释它;这是不道德和低效的)

Your C++ implementation general works above some operating system and communicate with it (using some implementation specific code, often in some system library). Generally that communication is done thru system calls. Look for instance into syscalls(2) for a list of system calls available on the Linux kernel.

您的c++实现一般工作在一些操作系统之上,并与它通信(使用一些实现特定的代码,通常在一些系统库中)。通常,通信是通过系统调用完成的。在syscalls(2)中查找Linux内核中可用的系统调用列表。

From the application point of view, a syscall is an elementary machine instruction like SYSENTER on x86-64 with some conventions (ABI)

从应用的角度来看,syscall是一种基本的机器指令,如x86-64上的SYSENTER,带有一些约定(ABI)

On my Linux desktop, the Qt libraries are above X11 client libraries communicating with the X11 server Xorg thru X Windows protocols.

在我的Linux桌面,Qt库位于与X11服务器Xorg通过X Windows协议通信的X11客户端库之上。

On Linux, use ldd on your executable to see the (long) list of dependencies on libraries. Use pmap on your running process to see which ones are "loaded" at runtime. BTW, on Linux, your application is probably using only free software, you could study its source code (from Qt, to Xlib, libc, ... the kernel) to understand more what is happening

在Linux上,在可执行文件上使用ldd查看库上的(长)依赖项列表。在运行过程中使用pmap来查看哪些在运行时被“加载”。在Linux上,您的应用程序可能只使用*软件,您可以研究它的源代码(从Qt,到Xlib, libc,…)了解更多正在发生的事情。

#5


19  

I think the concept you are missing is system calls. Each operating system provides an enormous amount of resources and functionality that you can tap into to do low-level operating system related things. Even when you call a regular library function, it is probably making a system call behind the scenes.

我认为您所缺少的概念是系统调用。每个操作系统都提供了大量的资源和功能,您可以利用这些资源和功能来完成低级操作系统相关的工作。即使调用常规库函数,它也可能在幕后进行系统调用。

System calls are a low-level way of making use of the power of the operating system, but can be complex and cumbersome to use, so are often "wrapped" in APIs so that you don't have to deal with them directly. But underneath, just about anything you do that involves O/S related resources will use system calls, including printing, networking and sockets, etc.

系统调用是一种利用操作系统功能的低级方法,但是使用起来可能很复杂、很麻烦,因此常常被“包装”在api中,这样您就不必直接处理它们。但是在底层,您所做的任何涉及O/S相关资源的事情都将使用系统调用,包括打印、网络和套接字等等。

In the case of windows, Microsoft Windows has its GUI actually written into the kernel, so there are system calls for making windows, painting graphics, etc. In other operating systems, the GUI may not be a part of the kernel, in which case as far as I know there wouldn't be any system calls for GUI related things, and you could only work at an even lower level with whatever low-level graphics and input related calls are available.

在windows操作系统中,微软windows的GUI实际上写进内核,所以有系统调用windows,绘画图形,等等。在其他操作系统中,GUI可能不是一个内核的一部分,在这种情况下,据我所知不会有任何系统调用GUI相关的东西,甚至你只能工作在一个低水平与低级图形和输入相关的调用是可用的。

#6


15  

Good question. Every new C or C++ developer has this in mind. I am assuming a standard x86 machine for the rest of this post. If you are using Microsoft C++ compiler, open your notepad and type this (name the file Test.c)

好问题。每个新的C或c++开发人员都考虑到了这一点。我假设这篇文章的其余部分是标准的x86机器。如果您正在使用Microsoft c++编译器,请打开记事本,输入以下内容(命名为Test.c文件)

int main(int argc, char **argv)
{
   return 0
}

And now compile this file (using developer command prompt) cl Test.c /FaTest.asm

现在编译这个文件(使用developer command prompt) cl测试。c / FaTest.asm

Now open Test.asm in your notepad. What you see is the translated code - C/C++ is translated to assembler. Do you get the hint ?

现在开启测试。在你的记事本asm。您看到的是被翻译的代码——C/ c++被翻译成汇编程序。明白了吗?

_main   PROC
    push    ebp
    mov ebp, esp
    xor eax, eax
    pop ebp
    ret 0
_main   ENDP

C/C++ programs are designed to run on the metal. Which means they have access to lower level hardware which makes it easier to exploit the capabilities of the hardware. Say, I am going to write a C library getch() on a x86 machine.

C/ c++程序是为在金属上运行而设计的。这意味着它们可以访问较低级别的硬件,从而更容易地利用硬件的功能。例如,我将在x86机器上编写一个C库getch()。

Depending on the assembler I would type something this way :

根据汇编程序,我可以这样输入:

_getch proc 
   xor AH, AH
   int 16h
   ;AL contains the keycode (AX is already there - so just return)
ret

I run it over with an assembler and generate a .OBJ - Name it getch.obj.

我用汇编程序运行它并生成一个。obj -命名为getch.obj。

I then write a C program (I dont #include anything)

然后我写了一个C程序(我什么都不写)

extern char getch();

void main(int, char **)
{
  getch();
}

Now name this file - GetChTest.c. Compile this file by passing getch.obj along. (Or compile individually to .obj and LINK GetChTest.Obj and getch.Obj together to produce GetChTest.exe).

现在将这个文件命名为GetChTest.c。通过通过getch来编译这个文件。obj。(或单独编译为.obj和LINK GetChTest。Obj getch。Obj一起生成GetChTest.exe)。

Run GetChTest.exe and you would find that it waits for the keyboard input.

GetChTest运行。你会发现它在等待键盘输入。

C/C++ programming is not just about language. To be a good C/C++ programmer you need to have a good understanding on the type of machine that it runs. You will need to know how the memory management is handled, how the registers are structured, etc., You may not need all these information for regular programming - but they would help you immensely. Apart from the basic hardware knowledge, it certainly helps if you understand how the compiler works (ie., how it translates) - which could enable you to tweak your code as necessary. It is an interesting package!

C/ c++编程不仅仅是语言。要成为一个优秀的C/ c++程序员,你需要对它运行的机器类型有一个很好的理解。您将需要了解内存管理是如何处理的,寄存器是如何结构的,等等,您可能不需要所有这些信息来进行常规编程——但是它们将极大地帮助您。除了基本的硬件知识之外,如果您理解编译器的工作原理(即),那么肯定会有所帮助。——它能使你在必要时调整你的代码。这是一个有趣的包裹!

Both languages support __asm keyword which means you could mix your assembly language code too. Learning C and C++ will make you a better rounded programmer overall.

两种语言都支持__asm关键字,这意味着您也可以混合汇编语言代码。学习C和c++会让你成为一个更全面的程序员。

It is not necessary to always link with Assembler. I had mentioned it because I thought that would help you understand better. Mostly, most such library calls make use of system calls / APIs provided by the Operating System (the OS in turn does the hardware interaction stuff).

不需要总是与汇编程序链接。我提到这一点是因为我认为这会帮助你更好地理解。大多数情况下,大多数此类库调用都使用操作系统提供的系统调用/ api(操作系统依次执行硬件交互)。

#7


10  

How does C++ ... suddenly get such capabilities through libraries written in C++ themselves ?

c++如何……突然通过使用c++编写的库获得这样的功能?

There's nothing magical about using other libraries. Libraries are simple big bags of functions that you can call.

使用其他库没有什么神奇的。图书馆是一个简单的大包函数,你可以调用它。

Consider yourself writing a function like this

假设您正在编写这样的函数

void addExclamation(std::string &str)
{
    str.push_back('!');
}

Now if you include that file you can write addExclamation(myVeryOwnString);. Now you might ask, "how did C++ suddenly get the capability to add exclamation points to a string?" The answer is easy: you wrote a function to do that then you called it.

现在,如果包含该文件,您可以编写addex呼喊(myVeryOwnString);。现在您可能会问,“c++是如何突然获得向字符串添加感叹号的能力的?”答案很简单:你写了一个函数,然后调用它。

So to answer your question about how C++ can get capabilities to draw windows through libraries written in C++, the answer is the same. Someone else wrote function(s) to do that, and then compiled them and gave them to you in the form of a library.

因此,要回答关于c++如何通过用c++编写的库获得绘制窗口的功能的问题,答案是一样的。有人编写函数来实现这个目的,然后将它们编译并以库的形式提供给您。

The other questions answer how the window drawing actually works, but you sounded confused about how libraries work so I wanted to address the most fundamental part of your question.

其他问题回答了窗口绘制实际上是如何工作的,但是您对库是如何工作感到困惑,因此我想讨论您问题中最基本的部分。

#8


8  

The key is the possibility of the operating system to expose an API and a detailed description on how this API is to be used.

关键是操作系统公开API的可能性以及关于如何使用该API的详细描述。

The operating system offers a set of APIs with calling conventions. The calling convention is defining the way a parameter is given into the API and how results are returned and how to execute the actual call.

操作系统提供了一组具有调用约定的api。调用约定是定义向API中提供参数的方式、返回结果的方式以及如何执行实际调用。

Operating systems and the compilers creating code for them play nicely together, so you usually have not to think about it, just use it.

操作系统和为它们创建代码的编译器配合得很好,所以您通常不必考虑它,只需使用它。

#9


7  

There is no need for a special syntax for creating windows. All that is required is that the OS provides an API to create windows. Such an API consists of simple function calls for which C++ does provide syntax.

创建窗口不需要特殊的语法。所需要的是操作系统提供一个API来创建windows。这样的API由简单的函数调用组成,c++确实提供了语法。

Furthermore C and C++ are so called systems programming languages and are able to access arbitrary pointers (which might be mapped to some device by the hardware). Additionally, it is also fairly simple to call functions defined in assembly, which allows the full range of operations the processor provides. Therefore it is possible to write an OS itself using C or C++ and a small amount of assembly.

此外,C和c++被称为系统编程语言,并且能够访问任意指针(可能被硬件映射到某个设备)。此外,调用汇编中定义的函数也相当简单,这允许处理器提供完整的操作范围。因此,可以使用C或c++编写操作系统本身,并编写少量的程序集。

It should also be mentioned that Qt is a bad example, as it uses a so-called meta compiler to extend C++' syntax. This is however not related to it's ability to call into the APIs provided by the OS to actually draw or create windows.

还应该提到Qt是一个不好的例子,因为它使用了一个所谓的元编译器来扩展c++的语法。然而,这与调用OS提供的api来实际绘制或创建窗口的能力无关。

#10


7  

First, there's a little misunderstading, I think

首先,我认为这有一点误解

How does C++, which previously had no syntax capable of asking the OS for a window or a way to communicate through networks

c++以前没有任何语法可以向操作系统请求窗口或通过网络进行通信的方法,它是如何做到这一点的呢

There is no syntax for doing OS operations. It's the question of semantics.

操作系统操作没有语法。这是语义学的问题。

suddenly get such capabilities through libraries written in C++ themselves

突然通过使用c++编写的库获得这样的功能

Well, the operating system is writen mostly in C. You can use shared libraries (so, dll) to call the external code. Additionally, the operating system code can register system routines on syscalls* or interrupts which you can call using assembly. That shared libraries often just make that system calls for you, so you are spared using inline assembly.

操作系统主要是用c编写的,您可以使用共享库(因此,dll)调用外部代码。此外,操作系统代码可以在syscalls*或中断上注册系统例程,您可以使用assembly调用它们。共享库通常只调用系统调用,因此不需要使用内联程序集。

Here's the nice tutorial on that: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
It's for Linux, but the principles are the same.

这里有一个很棒的教程:http://www.win.tue.nl/~aeb/linux/lk/lk-4.html这是linux的,但是原理是一样的。

How the operating system is doing operations on graphic cards, network cards etc? It's a very broad thema, but mostly you need to access interrupts, ports or write some data to special memory region. Since that operations are protected, you need to call them through the operating system anyway.

操作系统是如何对图形卡、网卡等进行操作的?这是一个非常广泛的thema,但大多数情况下您需要访问中断、端口或将一些数据写入特定的内存区域。由于操作是受保护的,所以您需要通过操作系统调用它们。

#11


7  

In an attempt to provide a slightly different view to other answers, I shall answer like this.

为了对其他答案提供稍微不同的看法,我将这样回答。

(Disclaimer: I am simplifying things slightly, the situation I give is purely hypothetical and is written as a means of demonstrating concepts rather than being 100% true to life).

(免责声明:我把事情稍微简化了一点,我所给出的情况纯粹是假设的,是作为展示概念的手段而写的,而不是100%真实的生活)。

Think of things from the other perspective, imagine you've just written a simple operating system with basic threading, windowing and memory management capabilities. You want to implement a C++ library to let users program in C++ and do things like make windows, draw onto windows etc. The question is, how to do this.

从另一个角度来考虑问题,假设您刚刚编写了一个简单的操作系统,它具有基本的线程、窗口和内存管理功能。你想要实现一个c++库,让用户用c++编程,做一些事情,比如制作windows,绘制windows等等。

Firstly, since C++ compiles to machine code, you need to define a way to use machine code to interface with C++. This is where functions come in, functions accept arguments and give return values, thus they provide a standard way of transferring data between different sections of code. They do this by establishing something known as a calling convention.

首先,由于c++编译为机器码,您需要定义一种使用机器码与c++进行接口的方法。这就是函数的作用,函数接受参数并给出返回值,因此它们提供了在不同代码段之间传输数据的标准方法。他们通过建立一种称为调用约定的东西来实现这一点。

A calling convention states where and how arguments should be placed in memory so that a function can find them when it gets executed. When a function gets called, the calling function places the arguments in memory and then asks the CPU to jump over to the other function, where it does what it does before jumping back to where it was called from. This means that the code being called can be absolutely anything and it will not change how the function is called. In this case however, the code behind the function would be relevant to the operating system and would operate on the operating system's internal state.

一个调用约定声明了在什么地方以及如何将参数放置在内存中,以便函数在执行时能够找到它们。当一个函数被调用时,调用函数将参数放在内存中,然后要求CPU跳转到另一个函数,在返回到调用它的地方之前,它在那里执行它的操作。这意味着被调用的代码可以是任何东西,它不会改变函数的调用方式。然而,在这种情况下,函数背后的代码将与操作系统相关,并将对操作系统的内部状态进行操作。

So, many months later and you've got all your OS functions sorted out. Your user can call functions to create windows and draw onto them, they can make threads and all sorts of wonderful things. Here's the problem though, your OS's functions are going to be different to Linux's functions or Windows' functions. So you decide you need to give the user a standard interface so they can write portable code. Here is where QT comes in.

好几个月后,你把所有的操作系统功能都整理好了。你的用户可以调用函数来创建窗口并绘制它们,它们可以创建线程和各种奇妙的东西。但问题是,你的操作系统的功能与Linux的功能或Windows的功能不同。所以你需要给用户一个标准的界面,这样他们就可以编写可移植的代码。这就是QT的作用。

As you almost certainly know, QT has loads of useful classes and functions for doing the sorts of things that operating systems do, but in a way that appears independent of the underlying operating system. The way this works is that QT provides classes and functions that are uniform in the way they appear to the user, but the code behind the functions is different for each operating system. For example QT's QApplication::closeAllWindows() would actually be calling each operating system's specialised window closing function depending on the version used. In Windows it would most likely call CloseWindow(hwnd) whereas on an os using the X Window System, it would potentially call XDestroyWindow(display,window).

正如您几乎肯定知道的那样,QT有很多有用的类和函数来执行操作系统所做的工作,但其方式似乎与底层操作系统无关。它的工作方式是QT提供的类和函数在用户看来是一致的,但是每个操作系统的函数后面的代码是不同的。例如QT的QApplication::closeAllWindows()实际上会根据所使用的版本调用每个操作系统的专用窗口关闭函数。在Windows中,它最有可能调用关闭窗口(hwnd),而在使用X Window系统的操作系统上,它可能会调用XDestroyWindow(显示,窗口)。

As is evident, an operating system has many layers, all of which have to interact through interfaces of many varieties. There are many aspects I haven't even touched on, but to explain them all would take a very long time. If you are further interested in the inner workings of operating systems, I recommend checking out the OS dev wiki.

显而易见,操作系统有许多层,所有这些层都必须通过多种接口进行交互。有很多方面我都没有涉及到,但要解释它们都需要很长时间。如果您对操作系统的内部工作更感兴趣,我建议您查看OS dev wiki。

Bear in mind though that the reason many operating systems choose to expose interfaces to C/C++ is that they compile to machine code, they allow assembly instructions to be mixed in with their own code and they provide a great degree of freedom to the programmer.

请记住,许多操作系统选择将接口公开给C/ c++的原因是它们编译为机器码,它们允许将汇编指令与自己的代码混合在一起,它们为程序员提供了很大程度的*。

Again, there is a lot going on here. I would like to go on to explain how libraries like .so and .dll files do not have to be written in C/C++ and can be written in assembly or other languages, but I feel that if I add any more I might as well write an entire article, and as much as I'd love to do that I don't have a site to host it on.

这里还有很多。我想继续解释库,所以和. dll文件不需要用C / c++编写的,可以写在组装或其他语言,但是我觉得如果我添加任何更多的我也可以写一整篇文章,和我想一样,我没有网站主办。

#12


6  

When you try to draw something on the screen, your code calls some other piece of code which calls some other code (etc.) until finally there is a "system call", which is a special instruction that the CPU can execute. These instructions can be either written in assembly or can be written in C++ if the compiler supports their "intrinsics" (which are functions that the compiler handles "specially" by converting them into special code that the CPU can understand). Their job is to tell the operating system to do something.

当您尝试在屏幕上绘制一些东西时,您的代码会调用另一段代码,这段代码会调用一些其他的代码(等等),直到最后出现一个“系统调用”,这是CPU可以执行的特殊指令。如果编译器支持它们的“特性”(即编译器将它们转换成CPU能够理解的特殊代码),那么这些指令可以用汇编语言编写,也可以用c++编写。他们的工作是告诉操作系统做点什么。

When a system call happens, a function gets called that calls another function (etc.) until finally the display driver is told to draw something on the screen. At that point, the display driver looks at a particular region in physical memory which is actually not memory, but rather an address range that can be written to as if it were memory. Instead, however, writing to that address range causes the graphics hardware to intercept the memory write, and draw something on the screen.
Writing to this region of memory is something that could be coded in C++, since on the software side it's just a regular memory access. It's just that the hardware handles it differently.
So that's a really basic explanation of how it can work.

当系统调用发生时,将调用一个调用另一个函数(等等)的函数,直到最终指示显示驱动程序在屏幕上绘制一些东西。此时,显示驱动程序查看物理内存中的一个特定区域,它实际上不是内存,而是一个地址范围,可以像写入内存一样写入。然而,写到这个地址范围会导致图形硬件拦截内存写入,并在屏幕上绘制一些东西。编写到这个内存区域的代码可以用c++编写,因为在软件方面,它只是一个常规的内存访问。只是硬件处理方式不同。这就是它的基本原理。

#13


4  

Your C++ program is using Qt library (also coded in C++). The Qt library will be using Windows CreateWindowEx function (which was coded in C inside kernel32.dll). Or under Linux it may be using Xlib (also coded in C), but it could as well be sending the raw bytes that in X protocol mean "Please create a window for me".

您的c++程序正在使用Qt库(也用c++编写)。Qt库将使用Windows CreateWindowEx函数(在kernel32.dll中用C编写)。或者在Linux下,它可能使用Xlib(也用C编码),但它也可能发送原始字节,在X协议中,这意味着“请为我创建一个窗口”。

Related to your catch-22 question is the historical note that “the first C++ compiler was written in C++”, although actually it was a C compiler with a few C++ notions, enough so it could compile the first version, which could then compile itself.

与“第二十二条军规”问题相关的是“第一个c++编译器是用c++编写的”的历史注释,尽管它实际上是一个带有一些c++概念的C编译器,足够用来编译第一个版本,然后再编译它自己。

Similarly, the GCC compiler uses GCC extensions: it is first compiled to a version then used to recompile itself. (GCC build instructions)

类似地,GCC编译器使用GCC扩展:首先将它编译成一个版本,然后再重新编译它自己。(GCC指令)

#14


2  

How i see the question this is actually a compiler question.

我怎么看这个问题这实际上是一个编译器问题。

Look at it this way, you write a piece of code in Assembly(you can do it in any language) which translates your newly written language you want to call Z++ into Assembly, for simplicity lets call it a compiler (it is a compiler).

这样看,你在汇编中编写了一段代码(你可以用任何一种语言来做),它将你的新书写的语言转换成程序集,因为简单起见,我们把它称为编译器(它是一个编译器)。

Now you give this compiler some basic functions, so that you can write int, string, arrays etc. actually you give it enough abilities so that you can write the compiler itself in Z++. and now you have a compiler for Z++ written in Z++, pretty neat right.

现在你给这个编译器一些基本的函数,这样你就可以写int, string, array等等,你给它足够的能力,这样你就可以用Z++来写编译器了。现在你有了一个用Z++写的编译器,非常棒。

Whats even cooler is that now you can add abilities to that compiler using the abilities it already has, thus expanding the Z++ language with new features by using the previous features

更酷的是,现在您可以使用它已经拥有的能力向编译器添加功能,从而使用前面的特性扩展具有新特性的Z++语言。

An example, if you write enough code to draw a pixel in any color, then you can expand it using the Z++ to draw anything you want.

例如,如果您编写足够多的代码来绘制任何颜色的像素,那么您可以使用Z++来展开它来绘制任何您想要的东西。

#15


0  

The hardware is what allows this to happen. You can think of the graphics memory as a large array (consisting of every pixel on the screen). To draw to the screen you can write to this memory using C++ or any language that allows direct access to that memory. That memory just happens to be accessible by or located on the graphics card.

硬件是允许这种情况发生的。您可以将图形内存看作一个大数组(由屏幕上的每个像素组成)。要绘制到屏幕上,您可以使用c++或任何允许直接访问该内存的语言编写到该内存。这个内存恰好可以被显卡访问或位于显卡上。

On modern systems accessing the graphics memory directly would require writing a driver because of various restrictions so you use indirect means. Libraries that create a window (really just an image like any other image) and then write that image to the graphics memory which the GPU then displays on screen. Nothing has to be added to the language except the ability to write to specific memory locations, which is what pointers are for.

在现代系统中,由于各种限制,直接访问图形内存需要编写驱动程序,因此需要使用间接方法。库创建一个窗口(实际上和其他图像一样),然后将该图像写入图形内存,GPU随后将其显示在屏幕上。除了能够写入特定的内存位置之外,不需要向语言中添加任何东西,这就是指针的用途。

#1


187  

A computer is like an onion, it has many many layers, from the inner core of pure hardware to the outermost application layer. Each layer exposes parts of itself to the next outer layer, so that the outer layer may use some of the inner layers functionality.

计算机就像一个洋葱,它有许多层,从纯硬件的核心到最外层的应用层。每个层将自己的部分暴露给下一个外层,以便外层可以使用一些内部层的功能。

In the case of e.g. Windows the operating system exposes the so-called WIN32 API for applications running on Windows. The Qt library uses that API to provide applications using Qt to its own API. You use Qt, Qt uses WIN32, WIN32 uses lower levels of the Windows operating system, and so on until it's electrical signals in the hardware.

例如,Windows操作系统为运行在Windows上的应用程序公开了所谓的WIN32 API。Qt库使用该API为自己的API提供使用Qt的应用程序。你使用Qt, Qt使用WIN32, WIN32使用Windows操作系统的较低级别,等等,直到它成为硬件中的电子信号。

#2


59  

You're right that in general, libraries cannot make anything possible that isn't already possible.

您是对的,一般来说,库不能使任何不可能的事情成为可能。

But the libraries don't have to be written in C++ in order to be usable by a C++ program. Even if they are written in C++, they may internally use other libraries not written in C++. So the fact that C++ didn't provide any way to do it doesn't prevent it from being added, so long as there is some way to do it outside of C++.

但是这些库并不一定要用c++编写才能被c++程序使用。即使它们是用c++编写的,它们也可能在内部使用其他非用c++编写的库。因此,事实上c++没有提供任何实现它的方法,这并不能阻止它被添加,只要有某种方法可以在c++之外实现它。

At a quite low level, some functions called by C++ (or by C) will be written in assembly, and the assembly contains the required instructions to do whatever isn't possible (or isn't easy) in C++, for example to call a system function. At that point, that system call can do anything your computer is capable of, simply because there's nothing stopping it.

在相当低的级别上,c++(或C)调用的一些函数将在程序集中编写,并且程序集中包含了在c++中做任何不可能(或不容易)的操作所需的指令,例如调用系统函数。此时,系统调用可以做任何您的计算机能够做的事情,仅仅是因为没有任何东西阻止它。

#3


42  

C and C++ have 2 properties that allow all this extensibility that the OP is talking about.

C和c++有两个属性允许OP所讨论的所有可扩展性。

  1. C and C++ can access memory
  2. C和c++可以访问内存
  3. C and C++ can call assembly code for instructions not in the C or C++ language.
  4. C和c++可以调用汇编代码来获取不使用C或c++语言的指令。

In the kernel or in a basic non-protected mode platform, peripherals like the serial port or disk drive are mapped into memory map in the same way as RAM is. Memory is a series of switches and flipping the switches of the peripheral gets you serial port or disk drive to do useful things.

在内核或基本的非保护模式平台中,诸如串口或磁盘驱动器之类的外围设备被映射到内存映射中,其方式与RAM相同。内存是一系列的开关,打开外围设备的开关,让你的串口或磁盘驱动器做一些有用的事情。

In a protected mode operating system, when one wants to access the kernel from userspace (say when writing to the file system or to draw a pixel on the screen) one needs to make a system call. C has not instruction to make a system call but C can call assembler code that can trigger the correct system call which allows one's C code to talk to the kernel.

在受保护模式操作系统中,当您希望从userspace访问内核(比如在写入文件系统或在屏幕上绘制像素时)时,需要进行系统调用。C没有进行系统调用的指令,但是C可以调用可以触发正确的系统调用的汇编代码,从而允许C代码与内核对话。

In order to make programming a particular platform easier, system calls are wrapped in more complex functions what may perform some useful function within one's own program. One is free to call the system calls directly (using assembler) but it is probably easier to just make use of one of the wrapper functions that the platform supplies.

为了使编程变得更容易,系统调用被封装在更复杂的函数中,这些函数可以在自己的程序中执行一些有用的功能。可以直接调用系统调用(使用汇编程序),但是仅仅使用平台提供的一个包装函数可能更容易。

There is another level of API that are a lot more useful than a system call. Take for example malloc. Not only will this call the system to obtain large blocks of memory but will manage this memory by doing all the book keeping on what is take place.

还有一种API比系统调用更有用。例如malloc。这不仅会调用系统来获取大块的内存,而且还会通过保存正在发生的事情来管理这些内存。

Win32 APIs wrap some graphic functionality with a common platform widget set. Qt takes this a bit further by wrapping the Win32 (or X Windows) API in a cross platform way.

Win32 API使用通用平台小部件集包装一些图形功能。

Fundamentally though a C compiler turns C code into machine code and since the computer is designed to use machine code, you should expect C to be able to accomplish the lions share or what a computer can do. All that the wrapper libraries do is do the heavy lifting for you so that you don't have to.

虽然C编译器将C代码转换为机器码,而且由于计算机是用来使用机器码的,因此您应该期望C能够完成lions share或计算机可以做什么。包装库所做的就是为您完成繁重的工作,这样您就不必这样做了。

#4


22  

Languages (like C++11) are specifications, on paper, usually written in English. Look inside the latest C++11 draft (or buy the costly final spec from your ISO vendor).

语言(如c++ 11)是书面的规范,通常用英语编写。查看最新的c++ 11草案(或从您的ISO供应商购买昂贵的最终规范)。

You generally use a computer with some language implementation (You could in principle run a C++ program without any computer, e.g. using a bunch of human slaves interpreting it; that would be unethical and inefficient)

你通常使用一种语言实现的计算机(你可以在原则上运行一个没有任何计算机的c++程序,例如使用一群人来解释它;这是不道德和低效的)

Your C++ implementation general works above some operating system and communicate with it (using some implementation specific code, often in some system library). Generally that communication is done thru system calls. Look for instance into syscalls(2) for a list of system calls available on the Linux kernel.

您的c++实现一般工作在一些操作系统之上,并与它通信(使用一些实现特定的代码,通常在一些系统库中)。通常,通信是通过系统调用完成的。在syscalls(2)中查找Linux内核中可用的系统调用列表。

From the application point of view, a syscall is an elementary machine instruction like SYSENTER on x86-64 with some conventions (ABI)

从应用的角度来看,syscall是一种基本的机器指令,如x86-64上的SYSENTER,带有一些约定(ABI)

On my Linux desktop, the Qt libraries are above X11 client libraries communicating with the X11 server Xorg thru X Windows protocols.

在我的Linux桌面,Qt库位于与X11服务器Xorg通过X Windows协议通信的X11客户端库之上。

On Linux, use ldd on your executable to see the (long) list of dependencies on libraries. Use pmap on your running process to see which ones are "loaded" at runtime. BTW, on Linux, your application is probably using only free software, you could study its source code (from Qt, to Xlib, libc, ... the kernel) to understand more what is happening

在Linux上,在可执行文件上使用ldd查看库上的(长)依赖项列表。在运行过程中使用pmap来查看哪些在运行时被“加载”。在Linux上,您的应用程序可能只使用*软件,您可以研究它的源代码(从Qt,到Xlib, libc,…)了解更多正在发生的事情。

#5


19  

I think the concept you are missing is system calls. Each operating system provides an enormous amount of resources and functionality that you can tap into to do low-level operating system related things. Even when you call a regular library function, it is probably making a system call behind the scenes.

我认为您所缺少的概念是系统调用。每个操作系统都提供了大量的资源和功能,您可以利用这些资源和功能来完成低级操作系统相关的工作。即使调用常规库函数,它也可能在幕后进行系统调用。

System calls are a low-level way of making use of the power of the operating system, but can be complex and cumbersome to use, so are often "wrapped" in APIs so that you don't have to deal with them directly. But underneath, just about anything you do that involves O/S related resources will use system calls, including printing, networking and sockets, etc.

系统调用是一种利用操作系统功能的低级方法,但是使用起来可能很复杂、很麻烦,因此常常被“包装”在api中,这样您就不必直接处理它们。但是在底层,您所做的任何涉及O/S相关资源的事情都将使用系统调用,包括打印、网络和套接字等等。

In the case of windows, Microsoft Windows has its GUI actually written into the kernel, so there are system calls for making windows, painting graphics, etc. In other operating systems, the GUI may not be a part of the kernel, in which case as far as I know there wouldn't be any system calls for GUI related things, and you could only work at an even lower level with whatever low-level graphics and input related calls are available.

在windows操作系统中,微软windows的GUI实际上写进内核,所以有系统调用windows,绘画图形,等等。在其他操作系统中,GUI可能不是一个内核的一部分,在这种情况下,据我所知不会有任何系统调用GUI相关的东西,甚至你只能工作在一个低水平与低级图形和输入相关的调用是可用的。

#6


15  

Good question. Every new C or C++ developer has this in mind. I am assuming a standard x86 machine for the rest of this post. If you are using Microsoft C++ compiler, open your notepad and type this (name the file Test.c)

好问题。每个新的C或c++开发人员都考虑到了这一点。我假设这篇文章的其余部分是标准的x86机器。如果您正在使用Microsoft c++编译器,请打开记事本,输入以下内容(命名为Test.c文件)

int main(int argc, char **argv)
{
   return 0
}

And now compile this file (using developer command prompt) cl Test.c /FaTest.asm

现在编译这个文件(使用developer command prompt) cl测试。c / FaTest.asm

Now open Test.asm in your notepad. What you see is the translated code - C/C++ is translated to assembler. Do you get the hint ?

现在开启测试。在你的记事本asm。您看到的是被翻译的代码——C/ c++被翻译成汇编程序。明白了吗?

_main   PROC
    push    ebp
    mov ebp, esp
    xor eax, eax
    pop ebp
    ret 0
_main   ENDP

C/C++ programs are designed to run on the metal. Which means they have access to lower level hardware which makes it easier to exploit the capabilities of the hardware. Say, I am going to write a C library getch() on a x86 machine.

C/ c++程序是为在金属上运行而设计的。这意味着它们可以访问较低级别的硬件,从而更容易地利用硬件的功能。例如,我将在x86机器上编写一个C库getch()。

Depending on the assembler I would type something this way :

根据汇编程序,我可以这样输入:

_getch proc 
   xor AH, AH
   int 16h
   ;AL contains the keycode (AX is already there - so just return)
ret

I run it over with an assembler and generate a .OBJ - Name it getch.obj.

我用汇编程序运行它并生成一个。obj -命名为getch.obj。

I then write a C program (I dont #include anything)

然后我写了一个C程序(我什么都不写)

extern char getch();

void main(int, char **)
{
  getch();
}

Now name this file - GetChTest.c. Compile this file by passing getch.obj along. (Or compile individually to .obj and LINK GetChTest.Obj and getch.Obj together to produce GetChTest.exe).

现在将这个文件命名为GetChTest.c。通过通过getch来编译这个文件。obj。(或单独编译为.obj和LINK GetChTest。Obj getch。Obj一起生成GetChTest.exe)。

Run GetChTest.exe and you would find that it waits for the keyboard input.

GetChTest运行。你会发现它在等待键盘输入。

C/C++ programming is not just about language. To be a good C/C++ programmer you need to have a good understanding on the type of machine that it runs. You will need to know how the memory management is handled, how the registers are structured, etc., You may not need all these information for regular programming - but they would help you immensely. Apart from the basic hardware knowledge, it certainly helps if you understand how the compiler works (ie., how it translates) - which could enable you to tweak your code as necessary. It is an interesting package!

C/ c++编程不仅仅是语言。要成为一个优秀的C/ c++程序员,你需要对它运行的机器类型有一个很好的理解。您将需要了解内存管理是如何处理的,寄存器是如何结构的,等等,您可能不需要所有这些信息来进行常规编程——但是它们将极大地帮助您。除了基本的硬件知识之外,如果您理解编译器的工作原理(即),那么肯定会有所帮助。——它能使你在必要时调整你的代码。这是一个有趣的包裹!

Both languages support __asm keyword which means you could mix your assembly language code too. Learning C and C++ will make you a better rounded programmer overall.

两种语言都支持__asm关键字,这意味着您也可以混合汇编语言代码。学习C和c++会让你成为一个更全面的程序员。

It is not necessary to always link with Assembler. I had mentioned it because I thought that would help you understand better. Mostly, most such library calls make use of system calls / APIs provided by the Operating System (the OS in turn does the hardware interaction stuff).

不需要总是与汇编程序链接。我提到这一点是因为我认为这会帮助你更好地理解。大多数情况下,大多数此类库调用都使用操作系统提供的系统调用/ api(操作系统依次执行硬件交互)。

#7


10  

How does C++ ... suddenly get such capabilities through libraries written in C++ themselves ?

c++如何……突然通过使用c++编写的库获得这样的功能?

There's nothing magical about using other libraries. Libraries are simple big bags of functions that you can call.

使用其他库没有什么神奇的。图书馆是一个简单的大包函数,你可以调用它。

Consider yourself writing a function like this

假设您正在编写这样的函数

void addExclamation(std::string &str)
{
    str.push_back('!');
}

Now if you include that file you can write addExclamation(myVeryOwnString);. Now you might ask, "how did C++ suddenly get the capability to add exclamation points to a string?" The answer is easy: you wrote a function to do that then you called it.

现在,如果包含该文件,您可以编写addex呼喊(myVeryOwnString);。现在您可能会问,“c++是如何突然获得向字符串添加感叹号的能力的?”答案很简单:你写了一个函数,然后调用它。

So to answer your question about how C++ can get capabilities to draw windows through libraries written in C++, the answer is the same. Someone else wrote function(s) to do that, and then compiled them and gave them to you in the form of a library.

因此,要回答关于c++如何通过用c++编写的库获得绘制窗口的功能的问题,答案是一样的。有人编写函数来实现这个目的,然后将它们编译并以库的形式提供给您。

The other questions answer how the window drawing actually works, but you sounded confused about how libraries work so I wanted to address the most fundamental part of your question.

其他问题回答了窗口绘制实际上是如何工作的,但是您对库是如何工作感到困惑,因此我想讨论您问题中最基本的部分。

#8


8  

The key is the possibility of the operating system to expose an API and a detailed description on how this API is to be used.

关键是操作系统公开API的可能性以及关于如何使用该API的详细描述。

The operating system offers a set of APIs with calling conventions. The calling convention is defining the way a parameter is given into the API and how results are returned and how to execute the actual call.

操作系统提供了一组具有调用约定的api。调用约定是定义向API中提供参数的方式、返回结果的方式以及如何执行实际调用。

Operating systems and the compilers creating code for them play nicely together, so you usually have not to think about it, just use it.

操作系统和为它们创建代码的编译器配合得很好,所以您通常不必考虑它,只需使用它。

#9


7  

There is no need for a special syntax for creating windows. All that is required is that the OS provides an API to create windows. Such an API consists of simple function calls for which C++ does provide syntax.

创建窗口不需要特殊的语法。所需要的是操作系统提供一个API来创建windows。这样的API由简单的函数调用组成,c++确实提供了语法。

Furthermore C and C++ are so called systems programming languages and are able to access arbitrary pointers (which might be mapped to some device by the hardware). Additionally, it is also fairly simple to call functions defined in assembly, which allows the full range of operations the processor provides. Therefore it is possible to write an OS itself using C or C++ and a small amount of assembly.

此外,C和c++被称为系统编程语言,并且能够访问任意指针(可能被硬件映射到某个设备)。此外,调用汇编中定义的函数也相当简单,这允许处理器提供完整的操作范围。因此,可以使用C或c++编写操作系统本身,并编写少量的程序集。

It should also be mentioned that Qt is a bad example, as it uses a so-called meta compiler to extend C++' syntax. This is however not related to it's ability to call into the APIs provided by the OS to actually draw or create windows.

还应该提到Qt是一个不好的例子,因为它使用了一个所谓的元编译器来扩展c++的语法。然而,这与调用OS提供的api来实际绘制或创建窗口的能力无关。

#10


7  

First, there's a little misunderstading, I think

首先,我认为这有一点误解

How does C++, which previously had no syntax capable of asking the OS for a window or a way to communicate through networks

c++以前没有任何语法可以向操作系统请求窗口或通过网络进行通信的方法,它是如何做到这一点的呢

There is no syntax for doing OS operations. It's the question of semantics.

操作系统操作没有语法。这是语义学的问题。

suddenly get such capabilities through libraries written in C++ themselves

突然通过使用c++编写的库获得这样的功能

Well, the operating system is writen mostly in C. You can use shared libraries (so, dll) to call the external code. Additionally, the operating system code can register system routines on syscalls* or interrupts which you can call using assembly. That shared libraries often just make that system calls for you, so you are spared using inline assembly.

操作系统主要是用c编写的,您可以使用共享库(因此,dll)调用外部代码。此外,操作系统代码可以在syscalls*或中断上注册系统例程,您可以使用assembly调用它们。共享库通常只调用系统调用,因此不需要使用内联程序集。

Here's the nice tutorial on that: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
It's for Linux, but the principles are the same.

这里有一个很棒的教程:http://www.win.tue.nl/~aeb/linux/lk/lk-4.html这是linux的,但是原理是一样的。

How the operating system is doing operations on graphic cards, network cards etc? It's a very broad thema, but mostly you need to access interrupts, ports or write some data to special memory region. Since that operations are protected, you need to call them through the operating system anyway.

操作系统是如何对图形卡、网卡等进行操作的?这是一个非常广泛的thema,但大多数情况下您需要访问中断、端口或将一些数据写入特定的内存区域。由于操作是受保护的,所以您需要通过操作系统调用它们。

#11


7  

In an attempt to provide a slightly different view to other answers, I shall answer like this.

为了对其他答案提供稍微不同的看法,我将这样回答。

(Disclaimer: I am simplifying things slightly, the situation I give is purely hypothetical and is written as a means of demonstrating concepts rather than being 100% true to life).

(免责声明:我把事情稍微简化了一点,我所给出的情况纯粹是假设的,是作为展示概念的手段而写的,而不是100%真实的生活)。

Think of things from the other perspective, imagine you've just written a simple operating system with basic threading, windowing and memory management capabilities. You want to implement a C++ library to let users program in C++ and do things like make windows, draw onto windows etc. The question is, how to do this.

从另一个角度来考虑问题,假设您刚刚编写了一个简单的操作系统,它具有基本的线程、窗口和内存管理功能。你想要实现一个c++库,让用户用c++编程,做一些事情,比如制作windows,绘制windows等等。

Firstly, since C++ compiles to machine code, you need to define a way to use machine code to interface with C++. This is where functions come in, functions accept arguments and give return values, thus they provide a standard way of transferring data between different sections of code. They do this by establishing something known as a calling convention.

首先,由于c++编译为机器码,您需要定义一种使用机器码与c++进行接口的方法。这就是函数的作用,函数接受参数并给出返回值,因此它们提供了在不同代码段之间传输数据的标准方法。他们通过建立一种称为调用约定的东西来实现这一点。

A calling convention states where and how arguments should be placed in memory so that a function can find them when it gets executed. When a function gets called, the calling function places the arguments in memory and then asks the CPU to jump over to the other function, where it does what it does before jumping back to where it was called from. This means that the code being called can be absolutely anything and it will not change how the function is called. In this case however, the code behind the function would be relevant to the operating system and would operate on the operating system's internal state.

一个调用约定声明了在什么地方以及如何将参数放置在内存中,以便函数在执行时能够找到它们。当一个函数被调用时,调用函数将参数放在内存中,然后要求CPU跳转到另一个函数,在返回到调用它的地方之前,它在那里执行它的操作。这意味着被调用的代码可以是任何东西,它不会改变函数的调用方式。然而,在这种情况下,函数背后的代码将与操作系统相关,并将对操作系统的内部状态进行操作。

So, many months later and you've got all your OS functions sorted out. Your user can call functions to create windows and draw onto them, they can make threads and all sorts of wonderful things. Here's the problem though, your OS's functions are going to be different to Linux's functions or Windows' functions. So you decide you need to give the user a standard interface so they can write portable code. Here is where QT comes in.

好几个月后,你把所有的操作系统功能都整理好了。你的用户可以调用函数来创建窗口并绘制它们,它们可以创建线程和各种奇妙的东西。但问题是,你的操作系统的功能与Linux的功能或Windows的功能不同。所以你需要给用户一个标准的界面,这样他们就可以编写可移植的代码。这就是QT的作用。

As you almost certainly know, QT has loads of useful classes and functions for doing the sorts of things that operating systems do, but in a way that appears independent of the underlying operating system. The way this works is that QT provides classes and functions that are uniform in the way they appear to the user, but the code behind the functions is different for each operating system. For example QT's QApplication::closeAllWindows() would actually be calling each operating system's specialised window closing function depending on the version used. In Windows it would most likely call CloseWindow(hwnd) whereas on an os using the X Window System, it would potentially call XDestroyWindow(display,window).

正如您几乎肯定知道的那样,QT有很多有用的类和函数来执行操作系统所做的工作,但其方式似乎与底层操作系统无关。它的工作方式是QT提供的类和函数在用户看来是一致的,但是每个操作系统的函数后面的代码是不同的。例如QT的QApplication::closeAllWindows()实际上会根据所使用的版本调用每个操作系统的专用窗口关闭函数。在Windows中,它最有可能调用关闭窗口(hwnd),而在使用X Window系统的操作系统上,它可能会调用XDestroyWindow(显示,窗口)。

As is evident, an operating system has many layers, all of which have to interact through interfaces of many varieties. There are many aspects I haven't even touched on, but to explain them all would take a very long time. If you are further interested in the inner workings of operating systems, I recommend checking out the OS dev wiki.

显而易见,操作系统有许多层,所有这些层都必须通过多种接口进行交互。有很多方面我都没有涉及到,但要解释它们都需要很长时间。如果您对操作系统的内部工作更感兴趣,我建议您查看OS dev wiki。

Bear in mind though that the reason many operating systems choose to expose interfaces to C/C++ is that they compile to machine code, they allow assembly instructions to be mixed in with their own code and they provide a great degree of freedom to the programmer.

请记住,许多操作系统选择将接口公开给C/ c++的原因是它们编译为机器码,它们允许将汇编指令与自己的代码混合在一起,它们为程序员提供了很大程度的*。

Again, there is a lot going on here. I would like to go on to explain how libraries like .so and .dll files do not have to be written in C/C++ and can be written in assembly or other languages, but I feel that if I add any more I might as well write an entire article, and as much as I'd love to do that I don't have a site to host it on.

这里还有很多。我想继续解释库,所以和. dll文件不需要用C / c++编写的,可以写在组装或其他语言,但是我觉得如果我添加任何更多的我也可以写一整篇文章,和我想一样,我没有网站主办。

#12


6  

When you try to draw something on the screen, your code calls some other piece of code which calls some other code (etc.) until finally there is a "system call", which is a special instruction that the CPU can execute. These instructions can be either written in assembly or can be written in C++ if the compiler supports their "intrinsics" (which are functions that the compiler handles "specially" by converting them into special code that the CPU can understand). Their job is to tell the operating system to do something.

当您尝试在屏幕上绘制一些东西时,您的代码会调用另一段代码,这段代码会调用一些其他的代码(等等),直到最后出现一个“系统调用”,这是CPU可以执行的特殊指令。如果编译器支持它们的“特性”(即编译器将它们转换成CPU能够理解的特殊代码),那么这些指令可以用汇编语言编写,也可以用c++编写。他们的工作是告诉操作系统做点什么。

When a system call happens, a function gets called that calls another function (etc.) until finally the display driver is told to draw something on the screen. At that point, the display driver looks at a particular region in physical memory which is actually not memory, but rather an address range that can be written to as if it were memory. Instead, however, writing to that address range causes the graphics hardware to intercept the memory write, and draw something on the screen.
Writing to this region of memory is something that could be coded in C++, since on the software side it's just a regular memory access. It's just that the hardware handles it differently.
So that's a really basic explanation of how it can work.

当系统调用发生时,将调用一个调用另一个函数(等等)的函数,直到最终指示显示驱动程序在屏幕上绘制一些东西。此时,显示驱动程序查看物理内存中的一个特定区域,它实际上不是内存,而是一个地址范围,可以像写入内存一样写入。然而,写到这个地址范围会导致图形硬件拦截内存写入,并在屏幕上绘制一些东西。编写到这个内存区域的代码可以用c++编写,因为在软件方面,它只是一个常规的内存访问。只是硬件处理方式不同。这就是它的基本原理。

#13


4  

Your C++ program is using Qt library (also coded in C++). The Qt library will be using Windows CreateWindowEx function (which was coded in C inside kernel32.dll). Or under Linux it may be using Xlib (also coded in C), but it could as well be sending the raw bytes that in X protocol mean "Please create a window for me".

您的c++程序正在使用Qt库(也用c++编写)。Qt库将使用Windows CreateWindowEx函数(在kernel32.dll中用C编写)。或者在Linux下,它可能使用Xlib(也用C编码),但它也可能发送原始字节,在X协议中,这意味着“请为我创建一个窗口”。

Related to your catch-22 question is the historical note that “the first C++ compiler was written in C++”, although actually it was a C compiler with a few C++ notions, enough so it could compile the first version, which could then compile itself.

与“第二十二条军规”问题相关的是“第一个c++编译器是用c++编写的”的历史注释,尽管它实际上是一个带有一些c++概念的C编译器,足够用来编译第一个版本,然后再编译它自己。

Similarly, the GCC compiler uses GCC extensions: it is first compiled to a version then used to recompile itself. (GCC build instructions)

类似地,GCC编译器使用GCC扩展:首先将它编译成一个版本,然后再重新编译它自己。(GCC指令)

#14


2  

How i see the question this is actually a compiler question.

我怎么看这个问题这实际上是一个编译器问题。

Look at it this way, you write a piece of code in Assembly(you can do it in any language) which translates your newly written language you want to call Z++ into Assembly, for simplicity lets call it a compiler (it is a compiler).

这样看,你在汇编中编写了一段代码(你可以用任何一种语言来做),它将你的新书写的语言转换成程序集,因为简单起见,我们把它称为编译器(它是一个编译器)。

Now you give this compiler some basic functions, so that you can write int, string, arrays etc. actually you give it enough abilities so that you can write the compiler itself in Z++. and now you have a compiler for Z++ written in Z++, pretty neat right.

现在你给这个编译器一些基本的函数,这样你就可以写int, string, array等等,你给它足够的能力,这样你就可以用Z++来写编译器了。现在你有了一个用Z++写的编译器,非常棒。

Whats even cooler is that now you can add abilities to that compiler using the abilities it already has, thus expanding the Z++ language with new features by using the previous features

更酷的是,现在您可以使用它已经拥有的能力向编译器添加功能,从而使用前面的特性扩展具有新特性的Z++语言。

An example, if you write enough code to draw a pixel in any color, then you can expand it using the Z++ to draw anything you want.

例如,如果您编写足够多的代码来绘制任何颜色的像素,那么您可以使用Z++来展开它来绘制任何您想要的东西。

#15


0  

The hardware is what allows this to happen. You can think of the graphics memory as a large array (consisting of every pixel on the screen). To draw to the screen you can write to this memory using C++ or any language that allows direct access to that memory. That memory just happens to be accessible by or located on the graphics card.

硬件是允许这种情况发生的。您可以将图形内存看作一个大数组(由屏幕上的每个像素组成)。要绘制到屏幕上,您可以使用c++或任何允许直接访问该内存的语言编写到该内存。这个内存恰好可以被显卡访问或位于显卡上。

On modern systems accessing the graphics memory directly would require writing a driver because of various restrictions so you use indirect means. Libraries that create a window (really just an image like any other image) and then write that image to the graphics memory which the GPU then displays on screen. Nothing has to be added to the language except the ability to write to specific memory locations, which is what pointers are for.

在现代系统中,由于各种限制,直接访问图形内存需要编写驱动程序,因此需要使用间接方法。库创建一个窗口(实际上和其他图像一样),然后将该图像写入图形内存,GPU随后将其显示在屏幕上。除了能够写入特定的内存位置之外,不需要向语言中添加任何东西,这就是指针的用途。