我们可以说 C++ 依赖于平台吗?
我知道 C++ 使用编译器,并且这些编译器对于不同的平台是不同的。当我们使用编译器编译 C++ 代码时,例如:在 Windows 上,会创建.EXE格式的文件。
为什么.EXE文件依赖于操作系统/平台?
.EXE 文件中的格式是什么?
为什么我们不能在其他平台上运行它?
我们可以说 C++ 依赖于平台吗?
我知道 C++ 使用编译器,并且这些编译器对于不同的平台是不同的。当我们使用编译器编译 C++ 代码时,例如:在 Windows 上,会创建.EXE格式的文件。
为什么.EXE文件依赖于操作系统/平台?
.EXE 文件中的格式是什么?
为什么我们不能在其他平台上运行它?
这其实是一个比较广泛的话题。为简单起见,它归结为两件事:操作系统和 CPU 架构。
首先,*.exe 通常只有 Windows,因为它是Windows 操作系统知道如何执行的二进制代码。此外,操作系统知道如何将其转换为适合体系结构的代码(这就是为什么 Windows“只是兼容”的原因)。请注意,还有很多事情正在发生,但这是对正在发生的事情的(非常)高级抽象。
现在,编译器将采用 C++ 代码并为体系结构(即 x86、MIPS 等)生成其相应的汇编代码。通常编译器也有一个汇编器(或者它可以依赖的一个)。汇编器链接代码并生成硬件可以执行的二进制代码。有关此主题的更多信息,请查找有关热电联产的更多信息。
附加说明
考虑不依赖于平台的Java。Java 编译器生成在 Java 虚拟机 (JVM) 上运行的 Java 字节码。请务必注意,任何时候您希望运行 Java 应用程序都必须运行 Java 虚拟机。由于预编译的 JVM 知道如何在您的操作系统和 CPU 架构上运行,它可以运行其 Java 字节码并有效地为您的特定系统运行相应的操作。
在已编译的二进制文件(即来自 C++ 代码的文件)中,您拥有系统字节码。因此,Java 为您模拟的那种指令直接硬编码到 .exe 或您正在使用的任何二进制格式中。考虑以下示例:
请注意,此 java 代码最终必须在 JVM 中运行,并且不能独立运行。
Java Code:
System.out.println("hello") (To be compiled)
Compiled Java bytecode:
Print "hello" (To be run in JVM)
JVM:
(... some translation, maybe to architecture code - I forget exactly ...)
system_print_code "hello" (JVM translation to CPU specific)
与 C++(可以在独立模式下运行)相比:
C++ Code:
cout<< "hello";
Architecture Code:
some_assembly_routine "hello"
Binary output:
system_print_code "hello"
如果你对这在现实生活中的例子感到好奇,我在下面提供了一个。
C++ Source 我把它放在一个名为 hello.cpp 的文件中
#include <iostream>
int main() {
using namespace std;
cout << "Hello world!" << endl;
return 0;
}
程序集(从 C++ 源代码
生成)通过生成g++ -S hello.cpp
.file "test.c"
.section .rodata
.type _ZStL19piecewise_construct, @object
.size _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
.zero 1
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.LC0:
.string "Hello world!"
.text
.globl main
.type main, @function
main:
.LFB1493:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rsi
leaq _ZSt4cout(%rip), %rdi
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
movq %rax, %rdx
movq _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
movq %rax, %rsi
movq %rdx, %rdi
call _ZNSolsEPFRSoS_E@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1493:
.size main, .-main
.type _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1982:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L5
cmpl $65535, -8(%rbp)
jne .L5
leaq _ZStL8__ioinit(%rip), %rdi
call _ZNSt8ios_base4InitC1Ev@PLT
leaq __dso_handle(%rip), %rdx
leaq _ZStL8__ioinit(%rip), %rsi
movq _ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
movq %rax, %rdi
call __cxa_atexit@PLT
.L5:
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1982:
.size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1983:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $65535, %esi
movl $1, %edi
call _Z41__static_initialization_and_destruction_0ii
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1983:
.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
.section .init_array,"aw"
.align 8
.quad _GLOBAL__sub_I_main
.hidden __dso_handle
.ident "GCC: (GNU) 7.2.1 20171128"
.section .note.GNU-stack,"",@progbits
二进制输出(从程序集生成)g++ -c
这是十六进制形式
生成的二进制输出的未链接形式(即尚未完全填充符号位置) 。我使用xxd
.
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0100 3e00 0100 0000 0000 0000 0000 0000 ..>.............
00000020: 0000 0000 0000 0000 0807 0000 0000 0000 ................
00000030: 0000 0000 4000 0000 0000 4000 0f00 0e00 ....@.....@.....
00000040: 5548 89e5 488d 3500 0000 0048 8d3d 0000 UH..H.5....H.=..
00000050: 0000 e800 0000 0048 89c2 488b 0500 0000 .......H..H.....
00000060: 0048 89c6 4889 d7e8 0000 0000 b800 0000 .H..H...........
00000070: 005d c355 4889 e548 83ec 1089 7dfc 8975 .].UH..H....}..u
00000080: f883 7dfc 0175 3281 7df8 ffff 0000 7529 ..}..u2.}.....u)
00000090: 488d 3d00 0000 00e8 0000 0000 488d 1500 H.=.........H...
000000a0: 0000 0048 8d35 0000 0000 488b 0500 0000 ...H.5....H.....
000000b0: 0048 89c7 e800 0000 0090 c9c3 5548 89e5 .H..........UH..
000000c0: beff ff00 00bf 0100 0000 e8a4 ffff ff5d ...............]
000000d0: c300 4865 6c6c 6f20 776f 726c 6421 0000 ..Hello world!..
000000e0: 0000 0000 0000 0000 0047 4343 3a20 2847 .........GCC: (G
000000f0: 4e55 2920 372e 322e 3120 3230 3137 3131 NU) 7.2.1 201711
00000100: 3238 0000 0000 0000 1400 0000 0000 0000 28..............
00000110: 017a 5200 0178 1001 1b0c 0708 9001 0000 .zR..x..........
00000120: 1c00 0000 1c00 0000 0000 0000 3300 0000 ............3...
00000130: 0041 0e10 8602 430d 066e 0c07 0800 0000 .A....C..n......
00000140: 1c00 0000 3c00 0000 0000 0000 4900 0000 ....<.......I...
00000150: 0041 0e10 8602 430d 0602 440c 0708 0000 .A....C...D.....
00000160: 1c00 0000 5c00 0000 0000 0000 1500 0000 ....\...........
00000170: 0041 0e10 8602 430d 0650 0c07 0800 0000 .A....C..P......
00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000190: 0000 0000 0000 0000 0100 0000 0400 f1ff ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001b0: 0000 0000 0300 0100 0000 0000 0000 0000 ................
000001c0: 0000 0000 0000 0000 0000 0000 0300 0300 ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0300 0400 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0300 0500 ................
00000200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000210: 0800 0000 0100 0500 0000 0000 0000 0000 ................
00000220: 0100 0000 0000 0000 2300 0000 0100 0400 ........#.......
00000230: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000240: 3200 0000 0200 0100 3300 0000 0000 0000 2.......3.......
00000250: 4900 0000 0000 0000 6200 0000 0200 0100 I.......b.......
00000260: 7c00 0000 0000 0000 1500 0000 0000 0000 |...............
00000270: 0000 0000 0300 0600 0000 0000 0000 0000 ................
00000280: 0000 0000 0000 0000 0000 0000 0300 0900 ................
00000290: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000002a0: 0000 0000 0300 0a00 0000 0000 0000 0000 ................
000002b0: 0000 0000 0000 0000 0000 0000 0300 0800 ................
000002c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000002d0: 7100 0000 1200 0100 0000 0000 0000 0000 q...............
000002e0: 3300 0000 0000 0000 7600 0000 1000 0000 3.......v.......
000002f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000300: 8000 0000 1000 0000 0000 0000 0000 0000 ................
00000310: 0000 0000 0000 0000 9600 0000 1000 0000 ................
00000320: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000330: ce00 0000 1000 0000 0000 0000 0000 0000 ................
00000340: 0000 0000 0000 0000 0901 0000 1000 0000 ................
00000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000360: 1a01 0000 1000 0000 0000 0000 0000 0000 ................
00000370: 0000 0000 0000 0000 3201 0000 1002 0000 ........2.......
00000380: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000390: 3f01 0000 1000 0000 0000 0000 0000 0000 ?...............
000003a0: 0000 0000 0000 0000 5701 0000 1000 0000 ........W.......
000003b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003c0: 0074 6573 742e 6300 5f5a 5374 4c31 3970 .test.c._ZStL19p
000003d0: 6965 6365 7769 7365 5f63 6f6e 7374 7275 iecewise_constru
000003e0: 6374 005f 5a53 744c 385f 5f69 6f69 6e69 ct._ZStL8__ioini
000003f0: 7400 5f5a 3431 5f5f 7374 6174 6963 5f69 t._Z41__static_i
00000400: 6e69 7469 616c 697a 6174 696f 6e5f 616e nitialization_an
00000410: 645f 6465 7374 7275 6374 696f 6e5f 3069 d_destruction_0i
00000420: 6900 5f47 4c4f 4241 4c5f 5f73 7562 5f49 i._GLOBAL__sub_I
00000430: 5f6d 6169 6e00 5f5a 5374 3463 6f75 7400 _main._ZSt4cout.
00000440: 5f47 4c4f 4241 4c5f 4f46 4653 4554 5f54 _GLOBAL_OFFSET_T
00000450: 4142 4c45 5f00 5f5a 5374 6c73 4953 7431 ABLE_._ZStlsISt1
00000460: 3163 6861 725f 7472 6169 7473 4963 4545 1char_traitsIcEE
00000470: 5253 7431 3362 6173 6963 5f6f 7374 7265 RSt13basic_ostre
00000480: 616d 4963 545f 4553 355f 504b 6300 5f5a amIcT_ES5_PKc._Z
00000490: 5374 3465 6e64 6c49 6353 7431 3163 6861 St4endlIcSt11cha
000004a0: 725f 7472 6169 7473 4963 4545 5253 7431 r_traitsIcEERSt1
000004b0: 3362 6173 6963 5f6f 7374 7265 616d 4954 3basic_ostreamIT
000004c0: 5f54 305f 4553 365f 005f 5a4e 536f 6c73 _T0_ES6_._ZNSols
000004d0: 4550 4652 536f 535f 4500 5f5a 4e53 7438 EPFRSoS_E._ZNSt8
000004e0: 696f 735f 6261 7365 3449 6e69 7443 3145 ios_base4InitC1E
000004f0: 7600 5f5f 6473 6f5f 6861 6e64 6c65 005f v.__dso_handle._
00000500: 5a4e 5374 3869 6f73 5f62 6173 6534 496e ZNSt8ios_base4In
00000510: 6974 4431 4576 005f 5f63 7861 5f61 7465 itD1Ev.__cxa_ate
00000520: 7869 7400 0000 0000 0700 0000 0000 0000 xit.............
00000530: 0200 0000 0500 0000 fdff ffff ffff ffff ................
00000540: 0e00 0000 0000 0000 0200 0000 0f00 0000 ................
00000550: fcff ffff ffff ffff 1300 0000 0000 0000 ................
00000560: 0400 0000 1100 0000 fcff ffff ffff ffff ................
00000570: 1d00 0000 0000 0000 2a00 0000 1200 0000 ........*.......
00000580: fcff ffff ffff ffff 2800 0000 0000 0000 ........(.......
00000590: 0400 0000 1300 0000 fcff ffff ffff ffff ................
000005a0: 5300 0000 0000 0000 0200 0000 0400 0000 S...............
000005b0: fcff ffff ffff ffff 5800 0000 0000 0000 ........X.......
000005c0: 0400 0000 1400 0000 fcff ffff ffff ffff ................
000005d0: 5f00 0000 0000 0000 0200 0000 1500 0000 _...............
000005e0: fcff ffff ffff ffff 6600 0000 0000 0000 ........f.......
000005f0: 0200 0000 0400 0000 fcff ffff ffff ffff ................
00000600: 6d00 0000 0000 0000 2a00 0000 1600 0000 m.......*.......
00000610: fcff ffff ffff ffff 7500 0000 0000 0000 ........u.......
00000620: 0400 0000 1700 0000 fcff ffff ffff ffff ................
00000630: 0000 0000 0000 0000 0100 0000 0200 0000 ................
00000640: 7c00 0000 0000 0000 2000 0000 0000 0000 |....... .......
00000650: 0200 0000 0200 0000 0000 0000 0000 0000 ................
00000660: 4000 0000 0000 0000 0200 0000 0200 0000 @...............
00000670: 3300 0000 0000 0000 6000 0000 0000 0000 3.......`.......
00000680: 0200 0000 0200 0000 7c00 0000 0000 0000 ........|.......
00000690: 002e 7379 6d74 6162 002e 7374 7274 6162 ..symtab..strtab
000006a0: 002e 7368 7374 7274 6162 002e 7265 6c61 ..shstrtab..rela
000006b0: 2e74 6578 7400 2e64 6174 6100 2e62 7373 .text..data..bss
000006c0: 002e 726f 6461 7461 002e 7265 6c61 2e69 ..rodata..rela.i
000006d0: 6e69 745f 6172 7261 7900 2e63 6f6d 6d65 nit_array..comme
000006e0: 6e74 002e 6e6f 7465 2e47 4e55 2d73 7461 nt..note.GNU-sta
000006f0: 636b 002e 7265 6c61 2e65 685f 6672 616d ck..rela.eh_fram
00000700: 6500 0000 0000 0000 0000 0000 0000 0000 e...............
00000710: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000720: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000730: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000740: 0000 0000 0000 0000 2000 0000 0100 0000 ........ .......
00000750: 0600 0000 0000 0000 0000 0000 0000 0000 ................
00000760: 4000 0000 0000 0000 9100 0000 0000 0000 @...............
00000770: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000780: 0000 0000 0000 0000 1b00 0000 0400 0000 ................
00000790: 4000 0000 0000 0000 0000 0000 0000 0000 @...............
000007a0: 2805 0000 0000 0000 0801 0000 0000 0000 (...............
000007b0: 0c00 0000 0100 0000 0800 0000 0000 0000 ................
000007c0: 1800 0000 0000 0000 2600 0000 0100 0000 ........&.......
000007d0: 0300 0000 0000 0000 0000 0000 0000 0000 ................
000007e0: d100 0000 0000 0000 0000 0000 0000 0000 ................
000007f0: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000800: 0000 0000 0000 0000 2c00 0000 0800 0000 ........,.......
00000810: 0300 0000 0000 0000 0000 0000 0000 0000 ................
00000820: d100 0000 0000 0000 0100 0000 0000 0000 ................
00000830: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000840: 0000 0000 0000 0000 3100 0000 0100 0000 ........1.......
00000850: 0200 0000 0000 0000 0000 0000 0000 0000 ................
00000860: d100 0000 0000 0000 0e00 0000 0000 0000 ................
00000870: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000880: 0000 0000 0000 0000 3e00 0000 0e00 0000 ........>.......
00000890: 0300 0000 0000 0000 0000 0000 0000 0000 ................
000008a0: e000 0000 0000 0000 0800 0000 0000 0000 ................
000008b0: 0000 0000 0000 0000 0800 0000 0000 0000 ................
000008c0: 0800 0000 0000 0000 3900 0000 0400 0000 ........9.......
000008d0: 4000 0000 0000 0000 0000 0000 0000 0000 @...............
000008e0: 3006 0000 0000 0000 1800 0000 0000 0000 0...............
000008f0: 0c00 0000 0600 0000 0800 0000 0000 0000 ................
00000900: 1800 0000 0000 0000 4a00 0000 0100 0000 ........J.......
00000910: 3000 0000 0000 0000 0000 0000 0000 0000 0...............
00000920: e800 0000 0000 0000 1b00 0000 0000 0000 ................
00000930: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000940: 0100 0000 0000 0000 5300 0000 0100 0000 ........S.......
00000950: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000960: 0301 0000 0000 0000 0000 0000 0000 0000 ................
00000970: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000980: 0000 0000 0000 0000 6800 0000 0100 0000 ........h.......
00000990: 0200 0000 0000 0000 0000 0000 0000 0000 ................
000009a0: 0801 0000 0000 0000 7800 0000 0000 0000 ........x.......
000009b0: 0000 0000 0000 0000 0800 0000 0000 0000 ................
000009c0: 0000 0000 0000 0000 6300 0000 0400 0000 ........c.......
000009d0: 4000 0000 0000 0000 0000 0000 0000 0000 @...............
000009e0: 4806 0000 0000 0000 4800 0000 0000 0000 H.......H.......
000009f0: 0c00 0000 0a00 0000 0800 0000 0000 0000 ................
00000a00: 1800 0000 0000 0000 0100 0000 0200 0000 ................
00000a10: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000a20: 8001 0000 0000 0000 4002 0000 0000 0000 ........@.......
00000a30: 0d00 0000 0e00 0000 0800 0000 0000 0000 ................
00000a40: 1800 0000 0000 0000 0900 0000 0300 0000 ................
00000a50: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000a60: c003 0000 0000 0000 6401 0000 0000 0000 ........d.......
00000a70: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000a80: 0000 0000 0000 0000 1100 0000 0300 0000 ................
00000a90: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000aa0: 9006 0000 0000 0000 7200 0000 0000 0000 ........r.......
00000ab0: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00000ac0: 0000 0000 0000 0000 ........
这些指令对应于 x86_64 机器。如果您有兴趣跟随和匹配操作码,您可以查看此参考资料或下载英特尔手册以了解完整性。同样,它是一个ELF文件,因此您可以观察到我们看到了我们期望的东西(即 的起始幻数0x7f
等)。
在任何情况下,一旦与系统链接(即 rung++ test.cpp
或g++ test.s
or g++ test.o
),这个可执行文件就会直接在您的操作系统之上运行。这和操作系统之间没有额外的翻译层。即便如此,操作系统仍然在做操作系统的事情,比如抽象硬件接口、管理系统资源等。
将其与原始问题联系起来,输出二进制文件在 Windows 机器上看起来会非常不同(对于相同的 C++ 代码)。至少,在 Windows 机器上,您会希望看到明显不是 ELF的可移植可执行 (PE) 格式的文件。
这与以下需要 JVM 运行的 Java 示例不同:
Java Source File
这被放置在一个名为Test.java
package mytest;
public class Test {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Java Byte Code (Generated from Java Source)
这是通过运行javac -d . Test.java
和运行输出文件(即mytest/Test.class
)生成的xxd
00000000: cafe babe 0000 0034 001d 0a00 0600 0f09 .......4........
00000010: 0010 0011 0800 120a 0013 0014 0700 1507 ................
00000020: 0016 0100 063c 696e 6974 3e01 0003 2829 .....<init>...()
00000030: 5601 0004 436f 6465 0100 0f4c 696e 654e V...Code...LineN
00000040: 756d 6265 7254 6162 6c65 0100 046d 6169 umberTable...mai
00000050: 6e01 0016 285b 4c6a 6176 612f 6c61 6e67 n...([Ljava/lang
00000060: 2f53 7472 696e 673b 2956 0100 0a53 6f75 /String;)V...Sou
00000070: 7263 6546 696c 6501 0009 5465 7374 2e6a rceFile...Test.j
00000080: 6176 610c 0007 0008 0700 170c 0018 0019 ava.............
00000090: 0100 0c48 656c 6c6f 2077 6f72 6c64 2107 ...Hello world!.
000000a0: 001a 0c00 1b00 1c01 000b 6d79 7465 7374 ..........mytest
000000b0: 2f54 6573 7401 0010 6a61 7661 2f6c 616e /Test...java/lan
000000c0: 672f 4f62 6a65 6374 0100 106a 6176 612f g/Object...java/
000000d0: 6c61 6e67 2f53 7973 7465 6d01 0003 6f75 lang/System...ou
000000e0: 7401 0015 4c6a 6176 612f 696f 2f50 7269 t...Ljava/io/Pri
000000f0: 6e74 5374 7265 616d 3b01 0013 6a61 7661 ntStream;...java
00000100: 2f69 6f2f 5072 696e 7453 7472 6561 6d01 /io/PrintStream.
00000110: 0007 7072 696e 746c 6e01 0015 284c 6a61 ..println...(Lja
00000120: 7661 2f6c 616e 672f 5374 7269 6e67 3b29 va/lang/String;)
00000130: 5600 2100 0500 0600 0000 0000 0200 0100 V.!.............
00000140: 0700 0800 0100 0900 0000 1d00 0100 0100 ................
00000150: 0000 052a b700 01b1 0000 0001 000a 0000 ...*............
00000160: 0006 0001 0000 0003 0009 000b 000c 0001 ................
00000170: 0009 0000 0025 0002 0001 0000 0009 b200 .....%..........
00000180: 0212 03b6 0004 b100 0000 0100 0a00 0000 ................
00000190: 0a00 0200 0000 0500 0800 0600 0100 0d00 ................
000001a0: 0000 0200 0e .....
正如所料,字节码输出以 0xCAFEBABE 开头。
然而,这里的关键区别是该代码不能直接运行。它仍然是二进制输出,但不打算由操作系统直接执行。如果您尝试在系统上没有 JVM 的情况下运行它,您只会得到一个错误。但是,此代码可以在包含兼容JVM的任何操作系统上运行。兼容的 JVM 集取决于您如何设置 source 和 target。默认情况下,它等同于您用于编译的 Java 版本。在这种情况下,我使用了 Java 8。
其工作方式是专门为每个系统编译 JVM(类似于上面的 C++ 示例),并将其二进制 Java 字节码转换为您的系统现在可以执行的内容。
归根结底,没有免费的午餐——正如 DanielKO 在评论中提到的,JVM 仍然是一个“平台”,但它比操作系统高一级,因此它看起来更便携。最终,在此过程中,代码必须转换为对您的特定操作系统系列和 CPU 架构有效的指令。但是,在 Java 和 JVM 的情况下,您只需为所有系统风格编译一个应用程序(即 JVM 本身)。那时,可以说,在 JVM 之上编写的所有内容都具有“免费”的系统支持(只要您的应用程序完全用 Java 编写并且不使用本机接口等)。
正如我之前提到的,这些信息有很多警告:) 这是一个非常简单的示例,旨在说明您可能实际观察到的内容。也就是说,我们没有涉及调用本机代码、使用自定义 JVM 代理或其他任何可能稍微影响这个答案的东西。然而,总的来说,这些更经常属于“特殊情况”的类别,除非您了解原因以及(希望)它们对可移植性的影响,否则您不会经常使用这些东西。
C++ 不依赖于平台——事实上,所有供应商都试图实现一个标准。您的意思是生成的 EXECUTABLE 是平台相关的。这是因为每个操作系统对有效可执行文件的构成都有不同的定义和要求。此外,每个操作系统都有一组不同的 API,用于实现需要由 C++ 链接器和编译器链接的核心服务。但这与 C++ 作为一种语言无关。
使诸如 C++ 之类的语言“独立于平台”的原因在于,它不依赖于给定 CPU 体系结构所青睐的语言结构。例如,汇编语言相对于 CPU 架构和指令集来说是非常特定的。对于它所针对的任何计算平台,C++ 编译器的前端(解析和语义分析)可以相同或基本相同。然而,仍然需要一个特定于平台或 CPU 的代码生成器(例如,用于 x86、ARM 等)。
EXE 是专门为 DOS/Windows 平台编译和代码生成的二进制文件。它的结构是 DOS/Windows 系统已知的,它包含有关如何在内存中定位可执行文件的信息以及特定于 CPU/平台以使其运行的所有指令代码。正如 Oleksandr 所指出的,它的具体格式可以在例如维基百科上找到。
实际上 C++ 不依赖于平台,但它产生的输出是 .exe 或其他格式,这取决于您使用的平台。所以简单地说C++的代码是独立于平台的,只是编译后的输出是依赖的。
C++ 本身不依赖于平台,但可以通过调用仅 Windows 和/或 Linux 的 API 来使用 C++ 编写依赖于平台的代码。如果您使用仅限 Microsoft 的 C++ 扩展等,也可能被锁定到特定平台。
给定平台的可执行格式是完全不同的联盟。
这个问题涉及的任何编程语言(例如 C++)都有两个重要方面:
第二个方面总是依赖于平台的,因为计算机必须使用在该计算机的特定处理器架构和操作系统上工作的机器代码、系统库等。
第一个方面可能依赖于平台,也可能不依赖于平台,具体取决于语言和您使用它的方式。
所以 *.exe 文件是一个依赖于平台的东西,因为它准确地说明了计算机将如何做你告诉它做的事情。但是 *.exe 文件不是 C++;它可能是从其他一些编程语言编译而来的。
C++ 程序可能依赖于平台,也可能不依赖于平台。如果您在 Windows 上调用编译器提供的函数而不是在其他操作系统中提供的函数,那么您的 C++ 程序将仅在 Windows 上编译。那是平台依赖。但是如果你避免调用那些依赖于平台的函数,你可以在任何地方编译 C++ 程序。
C++ 不依赖于平台。
除了 Windows,还有其他平台。
除了运行 Windows 的 X86 或 Pentium 之外,还有其他处理器。
这是一个称为“嵌入式系统”的领域,它在许多其他种类和品牌的操作系统和处理器上使用 C++ 语言。例如,有 DSP、老式的 8051 和 ARM 系列。
发明高级语言的原因是程序可以编写一次,但可以编译(翻译)到其他平台。例如,可以为 PDP 机器、Windows、Mac、Unix、Vrtx、Windriver、ARM 处理器编译独立于平台的 C++ 程序,所有这些都无需更改程序。
一般来说,可执行文件是平台相关的。