Krótka odpowiedź brzmi: większość konstrukcji językowych obsługiwanych przez C jest również obsługiwana przez mikroprocesor komputera docelowego, dlatego skompilowany kod C przekłada się bardzo ładnie i wydajnie na język asemblera mikroprocesora, co skutkuje mniejszym kodem i mniejszą powierzchnią.
Dłuższa odpowiedź wymaga trochę znajomości języka asemblera. W C stwierdzenie takie jak to:
int myInt = 10;
przetłumaczyłoby się na coś takiego w asemblerze:
myInt dw 1
mov myInt,10
Porównaj to z czymś takim jak C ++:
MyClass myClass;
myClass.set_myInt(10);
Wynikowy kod asemblera (w zależności od wielkości MyClass ()) może dodać do setek linii asemblera.
Bez faktycznego tworzenia programów w języku asemblera, czysty C jest prawdopodobnie „najbardziej chudym” i „najwęższym” kodem, w którym można stworzyć program.
EDYTOWAĆ
Biorąc pod uwagę komentarze do mojej odpowiedzi, zdecydowałem się przeprowadzić test, tylko dla własnego zdrowia psychicznego. Stworzyłem program o nazwie „test.c”, który wyglądał tak:
#include <stdio.h>
void main()
{
int myInt=10;
printf("%d\n", myInt);
}
Skompilowałem to do asemblacji przy użyciu gcc. Użyłem następującego wiersza poleceń, aby go skompilować:
gcc -S -O2 test.c
Oto wynikowy język asemblera:
.file "test.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
.section .text.unlikely,"ax",@progbits
.LCOLDB1:
.section .text.startup,"ax",@progbits
.LHOTB1:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB24:
.cfi_startproc
movl $10, %edx
movl $.LC0, %esi
movl $1, %edi
xorl %eax, %eax
jmp __printf_chk
.cfi_endproc
.LFE24:
.size main, .-main
.section .text.unlikely
.LCOLDE1:
.section .text.startup
.LHOTE1:
.ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
.section .note.GNU-stack,"",@progbits
Następnie tworzę plik o nazwie „test.cpp”, który definiuje klasę i wyświetla to samo, co „test.c”:
#include <iostream>
using namespace std;
class MyClass {
int myVar;
public:
void set_myVar(int);
int get_myVar(void);
};
void MyClass::set_myVar(int val)
{
myVar = val;
}
int MyClass::get_myVar(void)
{
return myVar;
}
int main()
{
MyClass myClass;
myClass.set_myVar(10);
cout << myClass.get_myVar() << endl;
return 0;
}
Skompilowałem to w ten sam sposób, używając tego polecenia:
g++ -O2 -S test.cpp
Oto wynikowy plik zespołu:
.file "test.cpp"
.section .text.unlikely,"ax",@progbits
.align 2
.LCOLDB0:
.text
.LHOTB0:
.align 2
.p2align 4,,15
.globl _ZN7MyClass9set_myVarEi
.type _ZN7MyClass9set_myVarEi, @function
_ZN7MyClass9set_myVarEi:
.LFB1047:
.cfi_startproc
movl %esi, (%rdi)
ret
.cfi_endproc
.LFE1047:
.size _ZN7MyClass9set_myVarEi, .-_ZN7MyClass9set_myVarEi
.section .text.unlikely
.LCOLDE0:
.text
.LHOTE0:
.section .text.unlikely
.align 2
.LCOLDB1:
.text
.LHOTB1:
.align 2
.p2align 4,,15
.globl _ZN7MyClass9get_myVarEv
.type _ZN7MyClass9get_myVarEv, @function
_ZN7MyClass9get_myVarEv:
.LFB1048:
.cfi_startproc
movl (%rdi), %eax
ret
.cfi_endproc
.LFE1048:
.size _ZN7MyClass9get_myVarEv, .-_ZN7MyClass9get_myVarEv
.section .text.unlikely
.LCOLDE1:
.text
.LHOTE1:
.section .text.unlikely
.LCOLDB2:
.section .text.startup,"ax",@progbits
.LHOTB2:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB1049:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $10, %esi
movl $_ZSt4cout, %edi
call _ZNSolsEi
movq %rax, %rdi
call _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE1049:
.size main, .-main
.section .text.unlikely
.LCOLDE2:
.section .text.startup
.LHOTE2:
.section .text.unlikely
.LCOLDB3:
.section .text.startup
.LHOTB3:
.p2align 4,,15
.type _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, @function
_GLOBAL__sub_I__ZN7MyClass9set_myVarEi:
.LFB1056:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $_ZStL8__ioinit, %edi
call _ZNSt8ios_base4InitC1Ev
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
addq $8, %rsp
.cfi_def_cfa_offset 8
jmp __cxa_atexit
.cfi_endproc
.LFE1056:
.size _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, .-_GLOBAL__sub_I__ZN7MyClass9set_myVarEi
.section .text.unlikely
.LCOLDE3:
.section .text.startup
.LHOTE3:
.section .init_array,"aw"
.align 8
.quad _GLOBAL__sub_I__ZN7MyClass9set_myVarEi
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.hidden __dso_handle
.ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
.section .note.GNU-stack,"",@progbits
Jak widać, wynikowy plik asemblera jest znacznie większy w pliku C ++ niż w pliku C. Nawet jeśli odetniesz wszystkie inne rzeczy i po prostu porównasz „główny” C z „głównym” C ++, jest wiele dodatkowych rzeczy.