1. 程式人生 > 其它 >計算機基礎知識學習筆記

計算機基礎知識學習筆記

計算機基礎知識學習筆記。

發現自己打比賽適應能力很差。。。常常沒有 devc++ 就打不好(主要是用不慣 gedit/vscode),因此決定先來學學計算機基礎知識(

1. 作業系統

作業系統,說白了就是一個有獨立的檔案系統、驅動程式,能夠獨立分配記憶體並與使用者進行互動的電腦程式,自主呼叫硬體資源。我們熟知的 Windows、Linux 就是作業系統,其他作業系統有 MacOS、iOS、Android 等。

當然,由於我們預設的作業系統是 windows,因此如果需要其他作業系統的環境(如 linux),就需要虛擬機器的幫助才能執行。虛擬機器是指能夠在完全隔離的條件下模擬一個作業系統的環境的軟體。舉個例子,通過將 linux 系統的環境儲存在一個字尾名為 .iso

(虛擬光碟機)的檔案中,再用虛擬機器為該系統分配一定的硬碟與記憶體就可以模擬虛擬的 linux 環境了,我們常聽說的“在 linux 下評測”就是指該虛擬的 linux 環境。常用的虛擬機器有 VMware Workstation,Virtual PC,Oracle VM Virtualbox(譬如在我原來的電腦上是 VMware,在學校電腦上是 Oracle)。

對於一個作業系統而言,為了使其能夠靈活呼叫硬體資源,需要驅動程式的驅動作用才能得以進行。驅動程式,說白了就是溝通硬體與計算機的程式。一個印表機之所以無法在新電腦上使用,是因為該電腦上沒有該印表機的驅動程式。windows 的驅動程式可以在目錄 C:\Windows\System32\drivers

下找到。注意,CPU、記憶體、主機板、軟碟機、鍵盤、顯示器等裝置並不需要安裝驅動程式,而音效卡、顯示卡、網絡卡等程式則需要。

沒有使用者的指令,作業系統不會隨意呼叫軟體和分配記憶體,在圖形介面出現之前,使用者則是以命令列的形式向計算機發送指令的,Windows 的命令提示符 cmd.exe 可以通過 Win+R 然後輸入 cmd,Linux 下的終端可以通過 Ctrl+Alt+T 開啟。作業系統的終端本質上是一種 Shell。或者說,Shell 是一個程式,一個二進位制可執行可執行的程式,它能夠處理人類使用者下達的命令。而每次我們開啟終端,系統就會自動開始呼叫這個程式。

2. Windows 命令列的使用

終於來了點和 OI 沾得上邊的東西了(

正如上面提到的,windows 的 cmd.exe 實際上是一種 shell,因此它也有對應的語法。更具體地,shell 其實是一種指令碼語言,類比 c++ 的 .cpp 檔案,以 .bat,.cmd 為字尾名的檔案則可以視作用 shell 為語言寫出來的原始碼。每次執行這樣的 .bat 檔案時,系統就會將該檔案中的所有命令扔到 cmd.exe 中一行行執行,這也就是所謂“指令碼語言”的含義,通俗地來說就是按照程式碼順序一行一行將其翻譯成機器能夠識別的資訊,常見的解釋語言還有 Python、PHP 和 JavaScript(.js 檔案)。常見的語言型別有機器語言(即用 01 寫成的、機器能夠直接識別的語言)、組合語言(則用 add,mov 等簡單助記識別符號寫成的,直接與記憶體相關的低階語言)、高階語言(獨立於機器,面向過程或物件的語言,指令碼語言就是一種解釋型的高階語言,即翻譯一句,執行一句,除此之外還有編譯型的高階語言,即先將其翻譯成組合語言,再通過靜態與動態連結生成可執行檔案,常見的編譯型語言有 C、C++、Fortran、Pascal,而 C# 和 Java 則是介於編譯型和解釋型之間的語言)

那麼 DOS 命令列的語法究竟有哪些呢?

  1. cls 命令(Linux 底下為 clear):無引數,用於清除螢幕
  2. cd 命令:任意時刻,命令列都會有一個路徑表示當前位於什麼目錄之下,cd 命令則可以指定一個子目錄並讓命令列進入這個子目錄。譬如 cd Desktop 則可以進入桌面。
  3. dir 命令(Linux 底下為 ls):顯示當前目錄中的子目錄及檔案的資訊。
  4. fc 命令(Linux 底下為 diff):fc A.txt B.txt 表示比較 A B 兩個檔案的內容,如果相同則會提示”找不到差異“,否則會列舉兩個檔案的不同之處。該命令常在對拍中出現。在後面加上 /w 可以忽略空格和 tab,在後面加上 /c 可以忽略大小寫問題。譬如,如果 A.txt 的內容為 A[space] ,B.txt 內容為 a,那麼 fc A.txt B.txt /c /w 則會提示”找不到差異“。
  5. mkdir 命令:rename A 表示新建一個叫 A 的目錄。
  6. rm 命令:刪除檔案/目錄:
    • rm -r A 刪除名叫 A 的目錄,此命令會將 A 在檔案搜尋樹中的所有子目錄遞迴刪除
    • rm -f A.txt 刪除名叫 A.txt 的檔案。值得注意的是,在這條命令中,A.txt 中可以含萬用字元,例如 rm -f *.txt 表示刪除所有後綴名為 .txt 的檔案。
  7. rename 命令:rename A B 表示將 A 重新命名為 B。
  8. echo 命令:echo A>B.txt 表示向 B.txt 輸出 A。
  9. A.exe 表示執行可執行檔案 A.exe,當然後面可以跟一些引數,這些引數會被傳到 main 函式的引數之內,argc 表示引數個數,argv 表示引數內容。譬如在使用 checker 的使用我們會呼叫 checker.exe in.txt out.txt ans.txt,此時 \(argc=3\)

當然還有一些和 g++ 有關的編譯命令。要使用這些命令,就必須加入配置 g++ 的環境變數,這裡就不贅述了,畢竟真實考場上的機子肯定是事先就配好環境變數的。

最常用的與 g++ 有關的命令是 g++ a.cpp -o a.exe(Linux 底下把 .exe 去掉)表示用 g++ 標準編譯 a.cpp 並生成可執行檔案 a.exe。那麼這四些引數究竟有什麼用呢?這就需要我們從 g++ 將原始碼轉化成可執行檔案的過程入手了。

首先貼一張圖片(來自 https://blog.csdn.net/a3192048/article/details/90143629):

從圖片中我們很清晰地看到,原始檔生成可執行檔案的過程,經歷了預編譯/預處理,編譯,彙編,連結這四個過程。經過四種操作生成的檔案分別被稱為“預處理程式碼”、“彙編程式碼”、“目的碼”和“可執行檔案”。

讓我們來著重檢視四個階段,首先是預編譯階段,假設我們現在有這麼一個 g++ 程式:

tmp4.cpp

//Created time: 2022/3/16 14:08:12
#include <cstdio>
int a,b;
int main(){
	scanf("%d%d",&a,&b);
	printf("%d",a+b);
	return 0;
}

我們首先執行命令 g++ -E tmp4.cpp -o tmp4.i,然後我們開啟 tmp4.i,由於篇幅原因,放上最後幾行:

static __attribute__ ((__unused__)) __inline__ __attribute__((__cdecl__))
                                                      __attribute__ ((__nonnull__ (2)))
int swprintf (wchar_t *__stream, const wchar_t *__format, ...)
{
  register int __retval;
  __builtin_va_list __local_argv;

  __builtin_va_start( __local_argv, __format );
  __retval = vswprintf( __stream, __format, __local_argv );
  __builtin_va_end( __local_argv );
  return __retval;
}

}
# 825 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 2 3
# 834 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 3
  __attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _vscwprintf(const wchar_t * __restrict__ _Format,va_list _ArgList);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _snwscanf(const wchar_t * __restrict__ _Src,size_t _MaxCount,const wchar_t * __restrict__ _Format,...);
  __attribute__ ((__dllimport__)) FILE *__attribute__((__cdecl__)) _wfdopen(int _FileHandle ,const wchar_t *_Mode);
  __attribute__ ((__dllimport__)) FILE *__attribute__((__cdecl__)) _wfopen(const wchar_t * __restrict__ _Filename,const wchar_t *__restrict__ _Mode) ;
  __attribute__ ((__dllimport__)) FILE *__attribute__((__cdecl__)) _wfreopen(const wchar_t * __restrict__ _Filename,const wchar_t * __restrict__ _Mode,FILE * __restrict__ _OldFile) ;



  __attribute__ ((__dllimport__)) void __attribute__((__cdecl__)) _wperror(const wchar_t *_ErrMsg);

  __attribute__ ((__dllimport__)) FILE *__attribute__((__cdecl__)) _wpopen(const wchar_t *_Command,const wchar_t *_Mode);




  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wremove(const wchar_t *_Filename);
  __attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wtmpnam(wchar_t *_Buffer);
  __attribute__ ((__dllimport__)) wint_t __attribute__((__cdecl__)) _fgetwc_nolock(FILE *_File);
  __attribute__ ((__dllimport__)) wint_t __attribute__((__cdecl__)) _fputwc_nolock(wchar_t _Ch,FILE *_File);
  __attribute__ ((__dllimport__)) wint_t __attribute__((__cdecl__)) _ungetwc_nolock(wint_t _Ch,FILE *_File);
# 884 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 3
  __attribute__ ((__dllimport__)) void __attribute__((__cdecl__)) _lock_file(FILE *_File);
  __attribute__ ((__dllimport__)) void __attribute__((__cdecl__)) _unlock_file(FILE *_File);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _fclose_nolock(FILE *_File);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _fflush_nolock(FILE *_File);
  __attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) _fread_nolock(void * __restrict__ _DstBuf,size_t _ElementSize,size_t _Count,FILE * __restrict__ _File);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _fseek_nolock(FILE *_File,long _Offset,int _Origin);
  __attribute__ ((__dllimport__)) long __attribute__((__cdecl__)) _ftell_nolock(FILE *_File);
  __extension__ __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _fseeki64_nolock(FILE *_File,long long _Offset,int _Origin);
  __extension__ __attribute__ ((__dllimport__)) long long __attribute__((__cdecl__)) _ftelli64_nolock(FILE *_File);
  __attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) _fwrite_nolock(const void * __restrict__ _DstBuf,size_t _Size,size_t _Count,FILE * __restrict__ _File);
  __attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _ungetc_nolock(int _Ch,FILE *_File);





  char *__attribute__((__cdecl__)) tempnam(const char *_Directory,const char *_FilePrefix) ;
  int __attribute__((__cdecl__)) fcloseall(void) ;
  FILE *__attribute__((__cdecl__)) fdopen(int _FileHandle,const char *_Format) ;
  int __attribute__((__cdecl__)) fgetchar(void) ;
  int __attribute__((__cdecl__)) fileno(FILE *_File) ;
  int __attribute__((__cdecl__)) flushall(void) ;
  int __attribute__((__cdecl__)) fputchar(int _Ch) ;
  int __attribute__((__cdecl__)) getw(FILE *_File) ;
  int __attribute__((__cdecl__)) putw(int _Ch,FILE *_File) ;
  int __attribute__((__cdecl__)) rmtmp(void) ;
# 926 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 3
int __attribute__((__cdecl__)) __mingw_str_wide_utf8 (const wchar_t * const wptr, char **mbptr, size_t * buflen);
# 940 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 3
int __attribute__((__cdecl__)) __mingw_str_utf8_wide (const char *const mbptr, wchar_t ** wptr, size_t * buflen);
# 949 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 3
void __attribute__((__cdecl__)) __mingw_str_free(void *ptr);




}

#pragma pack(pop)

# 1 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/sec_api/stdio_s.h" 1 3
# 9 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/sec_api/stdio_s.h" 3
# 1 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 1 3
# 10 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/sec_api/stdio_s.h" 2 3
# 960 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 2 3

# 1 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/_mingw_print_pop.h" 1 3
# 962 "D:/LenovoSoftstore/Install/DevC/MinGW64/x86_64-w64-mingw32/include/stdio.h" 2 3
# 43 "D:/LenovoSoftstore/Install/DevC/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/cstdio" 2 3
# 96 "D:/LenovoSoftstore/Install/DevC/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/cstdio" 3
namespace std
{
  using ::FILE;
  using ::fpos_t;

  using ::clearerr;
  using ::fclose;
  using ::feof;
  using ::ferror;
  using ::fflush;
  using ::fgetc;
  using ::fgetpos;
  using ::fgets;
  using ::fopen;
  using ::fprintf;
  using ::fputc;
  using ::fputs;
  using ::fread;
  using ::freopen;
  using ::fscanf;
  using ::fseek;
  using ::fsetpos;
  using ::ftell;
  using ::fwrite;
  using ::getc;
  using ::getchar;


  using ::gets;

  using ::perror;
  using ::printf;
  using ::putc;
  using ::putchar;
  using ::puts;
  using ::remove;
  using ::rename;
  using ::rewind;
  using ::scanf;
  using ::setbuf;
  using ::setvbuf;
  using ::sprintf;
  using ::sscanf;
  using ::tmpfile;

  using ::tmpnam;

  using ::ungetc;
  using ::vfprintf;
  using ::vprintf;
  using ::vsprintf;
}
# 157 "D:/LenovoSoftstore/Install/DevC/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/cstdio" 3
namespace __gnu_cxx
{
# 175 "D:/LenovoSoftstore/Install/DevC/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/cstdio" 3
  using ::snprintf;
  using ::vfscanf;
  using ::vscanf;
  using ::vsnprintf;
  using ::vsscanf;

}

namespace std
{
  using ::__gnu_cxx::snprintf;
  using ::__gnu_cxx::vfscanf;
  using ::__gnu_cxx::vscanf;
  using ::__gnu_cxx::vsnprintf;
  using ::__gnu_cxx::vsscanf;
}
# 3 "tmp4.cpp" 2
int a,b;
int main(){
 scanf("%d%d",&a,&b);
 printf("%d",a+b);
 return 0;
}

發現程式碼長達 41KB,917 行,然後我們開啟來一看,驚奇地發現裡面的東西還符合 g++ 的語法,並且如果你嘗試用 g++ 編譯生成的 .i 檔案,你會發現還是可以得到可執行檔案。這告訴我們,預編譯無非只是做了以下幾件事,並沒有完全改變程式碼的內容:

  1. 展開 define
  2. 展開所有 include
  3. 刪除所有註釋
  4. 處理所有 #ifdef#endif
  5. 新增行號和檔案識別符號
  6. 保留 #pragma 編譯器指令,在後面編譯階段使用。

接下來,我們執行 g++ tmp4.cpp -S,然後開啟 tmp4.s,發現裡面是用匯編語言寫成的程式碼

	.file	"tmp4.cpp"
	.section	.text$_Z5scanfPKcz,"x"
	.linkonce discard
	.globl	_Z5scanfPKcz
	.def	_Z5scanfPKcz;	.scl	2;	.type	32;	.endef
	.seh_proc	_Z5scanfPKcz
_Z5scanfPKcz:
.LFB2:
	pushq	%rbp
	.seh_pushreg	%rbp
	pushq	%rbx
	.seh_pushreg	%rbx
	subq	$56, %rsp
	.seh_stackalloc	56
	leaq	128(%rsp), %rbp
	.seh_setframe	%rbp, 128
	.seh_endprologue
	movq	%rdx, -40(%rbp)
	movq	%r8, -32(%rbp)
	movq	%r9, -24(%rbp)
	movq	%rcx, -48(%rbp)
	leaq	-40(%rbp), %rax
	movq	%rax, -88(%rbp)
	movq	-88(%rbp), %rax
	movq	%rax, %rdx
	movq	-48(%rbp), %rcx
	call	__mingw_vscanf
	movl	%eax, %ebx
	movl	%ebx, %eax
	addq	$56, %rsp
	popq	%rbx
	popq	%rbp
	ret
	.seh_endproc
	.section	.text$_Z6printfPKcz,"x"
	.linkonce discard
	.globl	_Z6printfPKcz
	.def	_Z6printfPKcz;	.scl	2;	.type	32;	.endef
	.seh_proc	_Z6printfPKcz
_Z6printfPKcz:
.LFB8:
	pushq	%rbp
	.seh_pushreg	%rbp
	pushq	%rbx
	.seh_pushreg	%rbx
	subq	$56, %rsp
	.seh_stackalloc	56
	leaq	128(%rsp), %rbp
	.seh_setframe	%rbp, 128
	.seh_endprologue
	movq	%rdx, -40(%rbp)
	movq	%r8, -32(%rbp)
	movq	%r9, -24(%rbp)
	movq	%rcx, -48(%rbp)
	leaq	-40(%rbp), %rax
	movq	%rax, -88(%rbp)
	movq	-88(%rbp), %rax
	movq	%rax, %rdx
	movq	-48(%rbp), %rcx
	call	__mingw_vprintf
	movl	%eax, %ebx
	movl	%ebx, %eax
	addq	$56, %rsp
	popq	%rbx
	popq	%rbp
	ret
	.seh_endproc
	.globl	a
	.bss
	.align 4
a:
	.space 4
	.globl	b
	.align 4
b:
	.space 4
	.def	__main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
.LC0:
	.ascii "%d%d\0"
.LC1:
	.ascii "%d\0"
	.text
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
main:
.LFB31:
	pushq	%rbp
	.seh_pushreg	%rbp
	movq	%rsp, %rbp
	.seh_setframe	%rbp, 0
	subq	$32, %rsp
	.seh_stackalloc	32
	.seh_endprologue
	call	__main
	leaq	b(%rip), %r8
	leaq	a(%rip), %rdx
	leaq	.LC0(%rip), %rcx
	call	_Z5scanfPKcz
	movl	a(%rip), %edx
	movl	b(%rip), %eax
	addl	%edx, %eax
	movl	%eax, %edx
	leaq	.LC1(%rip), %rcx
	call	_Z6printfPKcz
	movl	$0, %eax
	addq	$32, %rsp
	popq	%rbp
	ret
	.seh_endproc
	.ident	"GCC: (tdm64-1) 4.9.2"
	.def	__mingw_vscanf;	.scl	2;	.type	32;	.endef
	.def	__mingw_vprintf;	.scl	2;	.type	32;	.endef

顯然,此時得到的是經過編譯得到的彙編程式碼。g++ 形成的彙編程式碼中包含一些無用資訊,所有以 . 開頭的行都是在給彙編器和連結器下達命令,稱為“彙編器命令”。

接下來我們執行 g++ -c tmp4.cpp,然後開啟得到得到的 tmp4.o,如果你用記事本/devc++ 開啟的話會發現一堆亂碼,這裡我們用 sublime 開啟,發現有:

6486 0d00 0000 0000 4c04 0000 2500 0000
0000 0400 2e74 6578 7400 0000 0000 0000
0000 0000 5000 0000 1c02 0000 8403 0000
0000 0000 0900 0000 2000 5060 2e64 6174
6100 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
4000 50c0 2e62 7373 0000 0000 0000 0000
0000 0000 1000 0000 0000 0000 0000 0000
0000 0000 0000 0000 8000 50c0 2f34 0000
0000 0000 0000 0000 0000 0000 5000 0000
6c02 0000 de03 0000 0000 0000 0100 0000
2010 5060 2f32 3300 0000 0000 0000 0000
0000 0000 0c00 0000 bc02 0000 0000 0000
0000 0000 0000 0000 4010 3040 2f34 3300
0000 0000 0000 0000 0000 0000 0c00 0000
c802 0000 e803 0000 0000 0000 0300 0000
4010 3040 2f36 3300 0000 0000 0000 0000
0000 0000 5000 0000 d402 0000 0604 0000
0000 0000 0100 0000 2010 5060 2f38 3300
0000 0000 0000 0000 0000 0000 0c00 0000
2403 0000 0000 0000 0000 0000 0000 0000
4010 3040 2f31 3034 0000 0000 0000 0000
0000 0000 0c00 0000 3003 0000 1004 0000
0000 0000 0300 0000 4010 3040 2e72 6461
7461 0000 0000 0000 0000 0000 1000 0000
3c03 0000 0000 0000 0000 0000 0000 0000
4000 5040 2e78 6461 7461 0000 0000 0000
0000 0000 0c00 0000 4c03 0000 0000 0000
0000 0000 0000 0000 4000 3040 2e70 6461
7461 0000 0000 0000 0000 0000 0c00 0000
5803 0000 2e04 0000 0000 0000 0300 0000
4000 3040 2f31 3235 0000 0000 0000 0000
0000 0000 2000 0000 6403 0000 0000 0000
0000 0000 0000 0000 4000 5040 5548 89e5
4883 ec20 e800 0000 004c 8d05 0400 0000
488d 1500 0000 0048 8d0d 0000 0000 e800
0000 008b 1500 0000 008b 0504 0000 0001
d089 c248 8d0d 0500 0000 e800 0000 00b8
0000 0000 4883 c420 5dc3 9090 5553 4883
ec38 488d ac24 8000 0000 4889 55d8 4c89
45e0 4c89 4de8 4889 4dd0 488d 45d8 4889
45a8 488b 45a8 4889 c248 8b4d d0e8 0000
0000 89c3 89d8 4883 c438 5b5d c390 9090
9090 9090 9090 9090 9090 9090 010e 0485
0e03 0662 0230 0150 0000 0000 4100 0000
0000 0000 5553 4883 ec38 488d ac24 8000
0000 4889 55d8 4c89 45e0 4c89 4de8 4889
4dd0 488d 45d8 4889 45a8 488b 45a8 4889
c248 8b4d d0e8 0000 0000 89c3 89d8 4883
c438 5b5d c390 9090 9090 9090 9090 9090
9090 9090 010e 0485 0e03 0662 0230 0150
0000 0000 4100 0000 0000 0000 2564 2564
0025 6400 0000 0000 0000 0000 0108 0305
0832 0403 0150 0000 0000 0000 4e00 0000
0000 0000 4743 433a 2028 7464 6d36 342d
3129 2034 2e39 2e32 0000 0000 0000 0000
0000 0000 0900 0000 2200 0000 0400 1000
0000 0e00 0000 0400 1700 0000 0e00 0000
0400 1e00 0000 1800 0000 0400 2300 0000
0400 0000 0400 2900 0000 0e00 0000 0400
2f00 0000 0e00 0000 0400 3a00 0000 1800
0000 0400 3f00 0000 0800 0000 0400 3200
0000 2300 0000 0400 0000 0000 0200 0000
0300 0400 0000 0200 0000 0300 0800 0000
1000 0000 0300 3200 0000 2400 0000 0400
0000 0000 0600 0000 0300 0400 0000 0600
0000 0300 0800 0000 1400 0000 0300 0000
0000 0a00 0000 0300 0400 0000 0a00 0000
0300 0800 0000 1a00 0000 0300 2e66 696c
6500 0000 0000 0000 feff 0000 6701 746d
7034 2e63 7070 0000 0000 0000 0000 0000
0000 0000 8800 0000 0000 0000 0400 0000
0301 4100 0000 0100 0000 0000 0000 0000
0200 0000 0000 0000 9b00 0000 0000 0000
0400 2000 0201 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 a800 0000
0000 0000 0700 0000 0301 4100 0000 0100
0000 0000 0000 0000 0200 0000 0000 0000
bc00 0000 0000 0000 0700 2000 0200 6d61
696e 0000 0000 0000 0000 0100 2000 0200
2e74 6578 7400 0000 0000 0000 0100 0000
0301 4e00 0000 0900 0000 0000 0000 0000
0000 0000 2e64 6174 6100 0000 0000 0000
0200 0000 0301 0000 0000 0000 0000 0000
0000 0000 0000 0000 2e62 7373 0000 0000
0000 0000 0300 0000 0301 0800 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
ca00 0000 0000 0000 0500 0000 0301 0c00
0000 0000 0000 0000 0000 0000 0200 0000
0000 0000 de00 0000 0000 0000 0600 0000
0301 0c00 0000 0300 0000 0000 0000 0000
0200 0000 0000 0000 f200 0000 0000 0000
0800 0000 0301 0c00 0000 0000 0000 0000
0000 0000 0200 0000 0000 0000 0701 0000
0000 0000 0900 0000 0301 0c00 0000 0300
0000 0000 0000 0000 0200 0000 2e72 6461
7461 0000 0000 0000 0a00 0000 0301 0800
0000 0000 0000 0000 0000 0000 0000 0000
2e78 6461 7461 0000 0000 0000 0b00 0000
0301 0c00 0000 0000 0000 0000 0000 0000
0000 0000 2e70 6461 7461 0000 0000 0000
0c00 0000 0301 0c00 0000 0300 0000 0000
0000 0000 0000 0000 0000 0000 1c01 0000
0000 0000 0d00 0000 0301 1500 0000 0000
0000 0000 0000 0000 0000 0000 6100 0000
0000 0000 0000 0000 0300 0000 0200 6200
0000 0000 0000 0400 0000 0300 0000 0200
5f5f 6d61 696e 0000 0000 0000 0000 2000
0200 0000 0000 2701 0000 0000 0000 0000
2000 0200 0000 0000 3601 0000 0000 0000
0000 2000 0200 4601 0000 2e74 6578 7424
5f5a 3573 6361 6e66 504b 637a 002e 7864
6174 6124 5f5a 3573 6361 6e66 504b 637a
002e 7064 6174 6124 5f5a 3573 6361 6e66
504b 637a 002e 7465 7874 245f 5a36 7072
696e 7466 504b 637a 002e 7864 6174 6124
5f5a 3670 7269 6e74 6650 4b63 7a00 2e70
6461 7461 245f 5a36 7072 696e 7466 504b
637a 002e 7264 6174 6124 7a7a 7a00 2e74
6578 7424 5f5a 3573 6361 6e66 504b 637a
005f 5a35 7363 616e 6650 4b63 7a00 2e74
6578 7424 5f5a 3670 7269 6e74 6650 4b63
7a00 5f5a 3670 7269 6e74 6650 4b63 7a00
2e78 6461 7461 245f 5a35 7363 616e 6650
4b63 7a00 2e70 6461 7461 245f 5a35 7363
616e 6650 4b63 7a00 2e78 6461 7461 245f
5a36 7072 696e 7466 504b 637a 002e 7064
6174 6124 5f5a 3670 7269 6e74 6650 4b63
7a00 2e72 6461 7461 247a 7a7a 005f 5f6d
696e 6777 5f76 7363 616e 6600 5f5f 6d69
6e67 775f 7670 7269 6e74 6600 

很顯然,這時候編譯得到的東西就不是人能看得懂的程式碼,而是能夠被機器直接讀取的二進位制檔案了,這時候得到的就是目標檔案。

最後就是我們最常用的 g++ a.cpp -o a.exe 了,此命令能夠實現預編譯、編譯、彙編、連結四鍵合一。

這裡推薦一個專門可以檢視彙編程式碼的網站:https://gcc.godbolt.org/

講個笑話:這東西甚至可以卡常數!

https://codeforces.com/contest/1270/submission/149785206 是不是比上週五那發快一點……

具體方法就是:對於 windows 下評測的 OJ,把得到的彙編程式碼複製一遍,然後 __asm__(R"([換行符][在這裡粘上你的 .s檔案])") 即可。只要別作死在比賽中用就沒事……

編譯選項 -E/-o/-c/-S 聊完了,接下來講講編譯開關的事情,OIers 常用的編譯開關有以下幾個:

  • -O2 表示開啟 O2 優化,-O3-Ofast 也同理
  • -std=c++11 按 C++11 的標準來編譯程式。目前 NOIp 所用的開關都是 -std=c++14
  • -g,在編譯的時產生除錯資訊。
  • -lm 動態連結時將連線 GCC 的標準數學庫 libm.a(不過這個開關 g++ 預設是開著的),同理 -lc 表示連線 GCC 的標準 C 庫 libc.a-lgcc 表示連線 GCC 的標準支援庫 libgcc.a
  • -Wall 編譯時顯示最多除錯資訊。
  • -Wl,--stack=2147483648 將遞迴棧開到 \(2147483648\) 個位元組。
  • -Dmacro,等價於在程式中加入 #define macro,譬如 DONLINE_JUDGE 就等價於 #define ONLINE_JUDGE

最後一部分就是 DOS 的快捷鍵了。眾所周知,devc++ 編譯出來的程式並不是你寫的程式,而是系統呼叫了一個名叫 ConsolePauser.exe 的程式,然後把你寫的程式碼放進去執行。而 ConsolePauser 的介面就是 DOS 的介面,因此掌握一些 DOS 快捷鍵有關的知識還是有必要的:

  • Ctrl+Z:輸入 EOF 字元(在 Linux 底下是 Ctrl+D,當年 THUSC 時 D1T4 的 grader 用了 fread,然後我就倒騰了一年 THUWC 下的 EOF 是啥。。。。。。)
  • Ctrl+C:關閉視窗/結束程序,不是複製!
  • Ctrl+A:全選,這和一般的文字編輯器是一樣的。
  • Ctrl+V:貼上,也和一般的文字編輯器是一樣的。
  • Ctrl+H:回車。
  • 選中一部分後 Enter:複製。