多种语言打开计算器

多种语言打开计算器

涉及问题:程序如何与操作系统(OS)交互?
核心思路:一个程序(无论用什么语言写的)通过向上级领导——“操作系统“”请求”来“打开”另一个程序(比如计算器)。“请帮我运行一个叫做 calc.exe (Windows) / gnome-calculator (Linux) / Calculator.app (macOS) 的程序”
完成任务:如何在特定的编程语言中,去执行一个操作系统命令?——在不同语言的“工具箱”(标准库)里,找到那个负责“与操作系统沟通、执行命令”的工具

python

python 是“胶水语言”,它能轻松地将其他程序和组件“粘合”在一起,这也意味着它和操作系统交互的功能非常方便和直接。所以python用的工具箱是什么?os库。然后在找找os库的在线文档,看看哪个长的最像是“执行一个系统指令”的。我预先猜测可以是 systemrunexecute,还真让我找到了是 os.system()。这玩意打开计算器需要什么参数?更直接点,你在
windows cmd
里面输入的字符串calc打开计算器的,这个就是要的参数

# 需要一个能和操作系统交互的工具箱,所以先引入一个工具箱(标准库),os
# import os
import subprocess

# 在windows上打开计算器,命令calc
command = 'calc'
# 我需要工具箱里面的工具执行命令
# os.system(command)
subprocess.run(command)
print("计算器已打开")

py成功打开
推荐标准库subprocess,此库以更精细地控制子进程。
py进阶函数打开

Java

Java 流氓,“一次编写,到处运行”,它通过 Java 虚拟机(JVM)来隔离底层操作系统的差异。再俗一点,把 JVM 想象成一个为 Java 程序量身打造的、与世隔绝的“VIP 包间”。无论外面的世界是 Windows、Linux 还是 macOS,只要安装了对应的 JVM,Java 程序就能在这个标准化的包间里舒适地运行,不用关心外面操作系统的风风雨雨。
那么,Java 程序要怎么透过 JVM 去和特定的操作系统打交道呢?它要如何从“VIP 包间”里探出头来,跟外面的“大堂经理”(操作系统)点单呢?
JVM 为此提供了一个“运行时环境”的抽象。在 Java 里,这个“运行时环境”被抽象为Runtime类。然后就需要知道(获取)当前程序的 Runtime 对象是啥玩意,即是当前java程序所处的“运行时环境”,顺带看看这个对象提供了什么工具,能帮我们向操作系统“传话”。

涉及到java的反射机制,通常表现为get…(…)。俗一点,这涉及到 Java 的一个经典设计模式——单例模式。对于 Runtime 这种全局唯一的资源,Java 不让你 new 一个新的,而是通过一个静态方法 Runtime.getRuntime() 来获取那个已经存在的、唯一的实例。这感觉就像在问:“嘿,Java,把我们现在这个环境的管家叫来一下。”

拿到了 Runtime 对象这个管家后,找找它的工具手册里有没有听起来像是“执行”(execute)一个外部命令,exec()。exec()方法需要一个字符串参数,而我要用它来打开计算器,于是我填入参数calc

// 引入处理输入输出错误的工具,因为执行外部命令可能会失败
import java.io.IOException;

public class OpenCalculator {
    public static void main(String[] args) {
        System.out.println("我是一个Java程序,正准备通过JVM和操作系统聊聊...");

        try {
        // 1. 获取当前Java程序的运行时环境对象
        Runtime rt = Runtime.getRuntime();

        // 2. 告诉运行时环境,请它帮忙执行一个外部命令 "calc"
        // exec() 方法会返回一个 Process 对象,代表新创建的子进程(计算器)
        Process p = rt.exec("calc");

        System.out.println("已经把“打开计算器”的请求发出去了,操作系统应该收到了。");

        } catch (IOException e) {
            // 如果命令执行失败(比如找不到calc程序),就会抛出异常
            System.out.println("哎呀,出错了!");
            e.printStackTrace();
        }
    }
}

java成功打开计算器

os.system() 在 Python 里如果失败了,可能只是返回一个非零值,程序继续往下跑。而 Java 的 exec() 如果失败,会抛出一个 IOException,它强制你必须用 try...catch 来处理这种可能的“意外情况”。这就像是你在递交请求时,必须同时准备一个“如果请求被拒该怎么办”的预案。

与 Python 类似,Java 后来也提供了一个更强大、更灵活的工具 ProcessBuilder。它能让你更精细地配置要执行的命令、工作目录、环境变量等,是对 Runtime.exec() 的现代化升级,思想上和 Python 的 subprocess 库非常接近。

C/C++

C/C++ 作为系统级语言,与操作系统对话就像用「方言」直接喊话。它们的「杀手锏」藏在标准库 <stdlib.h> 中——system() 函数。怎么用呢?直接上代码:

#include <stdlib.h>

int main() {
    system("calc");  // 像在cmd里直接喊话
    return 0;
}

c打开计算器成功

批处理

如果说 C 是操作系统的“母语”,那批处理(.bat 文件)就是 Windows 命令行(CMD)的“方言”。它本身就不是一个独立的程序,而是写给命令行解释器的一系列指令清单

所以,它与操作系统的交互模式发生了根本变化:

  • 其他语言​:“你好操作系统,请你帮我运行一下 calc 这个命令。”
  • 批处理​:“我就是命令本身!下一条,calc!”

它不需要“请求”,它本身就在“执行”。因此,在批处理脚本里打开计算器,就是最原始、最直接的方式。

chcp 65001 > nul

@echo off
rem 这是一行注释,@echo off 的意思是不要在屏幕上显示我执行的每一条命令

echo 马上就要打开计算器了,请注意!

rem 直接写下程序名即可,就像你在CMD里输入的一样
calc

rem 为了能看到上面的提示,在这里暂停一下
pause

批处理打开计算器
让脚本不等待计算器关闭就继续往下走,可以使用 start 命令:

chcp 65001 > nul
@echo off
echo 我会打开计算器,但不会等它,我会继续做我自己的事。
start calc
echo 看,执行到这里了,计算器是不是在另一个窗口打开了?
pause

批处理打开计算器直接继续
不需要“工具箱”,因为它自己就是“命令行”本人

go

Go 语言是 Google 设计的一门现代化、注重工程效率的语言。它被设计用来编写高性能的系统软件,所以和操作系统打交道也是它的看家本领之一。

Go 的设计哲学是“显式”和“清晰”。它提供了一个专门的工具箱来处理这种事,名字也起得非常直白:os/exec 包。os 代表操作系统,exec 代表执行。

它的思路和 Python 的 subprocess 有点像,分为两步:

  1. 准备命令​:告诉 Go 你想执行什么命令和参数。
  2. 执行命令​:让准备好的命令真正运行起来。

这种方式比 C 的 system() 更安全、更可控。

// main.go 文件内容

// 告诉 Go 编译器,这个文件属于 "main" 包。
// "main" 包是一个特殊的包,它告诉 Go 这是一个可执行程序的入口,而不是一个库。
package main

// 引入我们需要的两个“工具箱”
import (
	"log"     // 一个简单的日志打印工具,比 fmt.Println 更适合输出程序状态信息。
	"os/exec" // 这就是go中与操作系统沟通、执行命令的核心工具箱。
)

// "main" 函数是程序的起点,Go 程序会从这里开始执行。
func main() {
	// 使用 exec.Command 函数来“准备”一个命令。
	// 这行代码本身并不会执行任何东西,它只是创建了一个代表“calc”命令的结构体。
	// 在 Windows 上是 "calc",在 macOS 上是 "open", "-a", "Calculator",在 Linux 上是 "gnome-calculator"
	cmd := exec.Command("calc")
    // 梦回小时候学习pascal了
 
	// 通过 log 工具打印一条信息,告诉我们程序进展到哪一步了。
	log.Println("Go程序准备就绪,即将请求操作系统打开计算器...")

	// 这是真正执行命令的一步!
	// cmd.Run() 会启动上面准备好的命令,并等待它执行完毕。
	// 它会返回一个 error 类型的值。在 Go 中,如果一个操作可能失败,通常会返回一个 error。
	err := cmd.Run()

	// 这是 Go 语言经典的错误处理方式。
	// 如果 err 不是 nil,就意味着在执行命令的过程中出了问题。
	if err != nil {
		// log.Fatalf 会打印错误信息,然后立刻终止程序。
		// %v 是一个占位符,会把 err 变量的内容格式化成字符串放进去。
		log.Fatalf("糟糕!命令执行失败了: %v", err)
	}

	// 如果程序能走到这一行,说明 cmd.Run() 没有返回错误,命令已成功发出。
	log.Println("请求已发送!请检查你的桌面,计算器应该已经打开了。")
}

go打开计算器

汇编

“硬核”部分来袭。如果说 C 是操作系统的“母语”,那汇编语言就是 CPU 能听懂的“机器指令”的助记符。这是最最底层的对话方式。

用汇编语言去打开计算器,不再是“请求”操作系统,而是直接**调用操作系统的“系统服务例程” (System Call)**​。这就像是直接推开CEO办公室的门,使用他提供给核心人员的内部接口。

这个过程​高度依赖于具体的操作系统和CPU架构​。Windows 和 Linux 的方式完全不同。我们以 32 位 Windows 为例,它提供了一个非常古老但简单的 API 函数叫做 WinExec,我们可以用汇编直接调用它。

这已经不是简单的写代码了,你需要理解程序的内存布局、函数调用约定等底层知识。

我使用了一个windows 2003虚拟机,我现在要做的,就是扮演编译器和链接器的角色,手动将“图纸”(.asm 源代码)打造成一个可以被 Windows 使用的“建筑”(.exe 文件)。而建东西是需要工具辅助的,用包含汇编器(ml.exe)、链接器(link.exe)以及代码中引用的所有 Windows 库和头文件的“工具箱”——MASM32 SDK,我认为是不错的选择。
MASM32 SDK 的官方网站:http://www.masm32.com/

我默认c盘

创建一个后缀为.asm的文件,这就是图纸

; opencalc.asm

; Intel 80386 处理器
; 32位保护的线性地址空间模型,被调函数规则stdcall,参数从右往左压栈
; casemap :none 使区分大小写
.386
.model flat, stdcall
option casemap :none

; 引入 Windows API 的定义库,这些都位于 C:\masm32\include
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

; 告诉链接器需要链接哪个库文件,这个位于 C:\masm32\lib
includelib \masm32\lib\kernel32.lib

.data
    ; 在数据段定义一个以0结尾的字符串,这是我们要执行的命令
    szCmdLine db "calc.exe", 0

.code
start:
    ; 调用 WinExec 函数。
    ; 第一个参数: 要执行的命令字符串的地址 (addr szCmdLine)
    ; 第二个参数: 窗口的显示方式 (SW_SHOWNORMAL 表示正常显示)
    invoke WinExec, addr szCmdLine, SW_SHOWNORMAL

    ; 调用 ExitProcess 正常退出程序,参数0表示没有错误
    invoke ExitProcess, 0

end start

编译和链接——从“蓝图”到“可执行文件”,

  1. 步骤 3.1: 汇编 (Assemble)
    这一步是将人类可读的 opencalc.asm 文件,翻译成机器可读但还不能独立运行的“目标文件”(.obj)。
    在命令提示符里,输入以下命令并按回车:
C:\masm32\bin\ml.exe /c /Zd /coff opencalc.asm

C:\masm32\bin\ml.exe: 这是 MASM32 的汇编器程序。

/c: 参数告诉它“只汇编,不要链接”。

/Zd: 添加调试信息。

/coff: 指定生成的目标文件格式为 COFF,这是 Windows 的标准格式。

opencalc.asm: 输入源文件。

执行后,如果没有报错,会生成一个新文件:opencalc.obj
2. 步骤 3.2: 链接 (Link)
这一步是将目标文件 opencalc.obj 和它所依赖的系统库(kernel32.lib)“链接”在一起,最终生成一个完整的、可以执行的 .exe 文件。

C:\masm32\bin\link.exe /SUBSYSTEM:WINDOWS /LIBPATH:C:\masm32\lib opencalc.obj

C:\masm32\bin\link.exe: 这是 MASM32 的链接器程序。

/SUBSYSTEM:WINDOWS: **非常重要!**这个参数告诉链接器,要生成的是一个窗口程序,而不是一个控制台(黑框框)程序。

/LIBPATH:C:\masm32\lib: 告诉链接器去哪里找库文件(比如 kernel32.lib)。

opencalc.obj: 我们的输入目标文件。

执行后,如果没有报错,最终成品:opencalc.exe

汇编打开计算器
悄咪咪记一下汇编应用小趣味

  1. 绕过系统调用限制
    直接通过汇编调用 syscall,不过需要考虑不同Windows版本:

    ; Linux下通过syscall启动计算器
    mov rax, 59          ; sys_execve系统调用号
    mov rdi, cmd         ; 命令字符串
    syscall
    
  2. Shellcode动态查找函数地址
    通过遍历PEB结构获取 kernel32.dll 基址:

    mov ebx, fs:[0x30]     ; 获取PEB地址
    mov ebx, [ebx+0x0C]    ; PEB_LDR_DATA结构
    mov ebx, [ebx+0x14]    ; InMemoryOrderModuleList
    ; ... 遍历链表找到kernel32.dll基址
    

易语言

这是一道附加小吃。如果说 C 是操作系统的“母语”,Python 是“胶水语言”,那么易语言就像是一个专门为 Windows 系统打造的​“图形化中文遥控器”
它的核心哲学就是,让不懂英文、不理解复杂 API 的人,也能通过拖拽控件和使用中文命令来快速开发 Windows 程序。它与操作系统的交互方式,是把最常用的系统功能,封装成了一个个简单直白的中文命令。

下载参考https://blog.youkuaiyun.com/qq_42363090/article/details/136952430

有时候语言学多了,就会丧失人性… 搞错了,简单的反而一下子摸不到头脑
1
很抽象,下一步添加一个触发按钮
2
3

易语言学习参考:https://www.eyuyan.com/help/day/day2.htm

4
5

写(。・∀・)ノ゙嗨了,顺带编译一下

6
7

如果出现编译不成功,链接器路径没对
error
error2
error3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxxBamboo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值