학습 기록 (Learning Logs)/CS Study
C, C++, C# 차이
devWonny
2024. 12. 7. 16:25
질문
C언어와 C++ 차이가 뭔가요?
C++ 개발자가 두명이 있어서,C언어와 C++ 차이가 뭐냐고 물어봤다.
궁금해서 정리해보려한다.
C++언어와 C# 차이가 뭔가요?
c언어는 절차 지향 프로그래밍 언어
c++ 객체 지향 프로그래밍 언어이다.
java는 객체 지향 프로그래밍 언어이다.
개인적 생각:
따라서 코드를 보면 c언어는 함수 나열로만 되어있어서 import를 해오는 부분이 많다.
반면 java에서는 객체를 선언하고, 객체 안에 있는 함수를 불러다가 사용하기 떄문에 어디서 어떤 함수가 실행되는지 파악하기 쉽다.
c와 c++차이는 결국 oop차이로 생각하면 될 듯 하다.
더더욱 사용하기 편하게! java처럼 만든것이 C#이다.
C 예제: 학생의 성적을 계산하는 프로그램
#include <stdio.h>
// 함수 선언
void inputStudentData(char name[], int scores[], int subjectCount);
float calculateAverage(int scores[], int subjectCount);
void printResult(char name[], float average);
int main() {
char studentName[50];
int scores[5]; // 최대 5과목 점수
int subjectCount = 5;
// 1. 학생 데이터 입력
inputStudentData(studentName, scores, subjectCount);
// 2. 평균 계산
float average = calculateAverage(scores, subjectCount);
// 3. 결과 출력
printResult(studentName, average);
return 0;
}
// 학생 데이터 입력 함수
void inputStudentData(char name[], int scores[], int subjectCount) {
printf("학생 이름을 입력하세요: ");
scanf("%s", name);
for (int i = 0; i < subjectCount; i++) {
printf("과목 %d의 점수를 입력하세요: ", i + 1);
scanf("%d", &scores[i]);
}
}
// 평균 계산 함수
float calculateAverage(int scores[], int subjectCount) {
int total = 0;
for (int i = 0; i < subjectCount; i++) {
total += scores[i];
}
return (float)total / subjectCount;
}
// 결과 출력 함수
void printResult(char name[], float average) {
printf("\n학생 이름: %s\n", name);
printf("평균 점수: %.2f\n", average);
if (average >= 60) {
printf("결과: 합격\n");
} else {
printf("결과: 불합격\n");
}
}
C++ 예제: 학생의 성적을 계산하는 프로그램
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 학생 데이터를 표현하는 클래스
class Student {
private:
string name; // 학생 이름
vector<int> scores; // 학생 점수
float average; // 평균 점수
public:
// 학생 데이터 입력
void inputStudentData() {
cout << "학생 이름을 입력하세요: ";
cin >> name;
int subjectCount;
cout << "과목 수를 입력하세요: ";
cin >> subjectCount;
scores.resize(subjectCount);
for (int i = 0; i < subjectCount; i++) {
cout << "과목 " << i + 1 << "의 점수를 입력하세요: ";
cin >> scores[i];
}
}
// 평균 계산
void calculateAverage() {
int total = 0;
for (int score : scores) {
total += score;
}
average = static_cast<float>(total) / scores.size();
}
// 결과 출력
void printResult() const {
cout << "\n학생 이름: " << name << endl;
cout << "평균 점수: " << average << endl;
if (average >= 60) {
cout << "결과: 합격" << endl;
} else {
cout << "결과: 불합격" << endl;
}
}
};
int main() {
Student student; // Student 객체 생성
// 학생 데이터 입력, 평균 계산, 결과 출력
student.inputStudentData();
student.calculateAverage();
student.printResult();
return 0;
}
OOP의 장점이 느껴지지 않는가?
Student의 구성요소는 name, scores, average로 되어있는것을 알수있다.
Student 는 inputStudentData(), calculateAverage(), printResult() 함수를 소지하고 있다.
반면 c언어는 쭈우우우우욱 읽어야 해석이 가능하다.
c언에서 이름, 점수, 평균: char studentName[50];, int scores[5]; // 최대 5과목 점수, float average
c#은 이벤트 프로그래밍이 가능해진다.
java는 클래스로 한번 캡슐화한다. 묶어서 생각하기때문에 어디 출신인지 파악이 가능하다.
반면 c언어는 계속해서 추적해야한다.
C는 클래스, 상속, 다형성이 없다. 따라서 재사용성이 낮아진다.
C#은 자바처럼 다중상속을 막고, 인터페이스로 더욱더 다형성에 힘을 싣는다.
C++ 다중 상속 예시:
class A { public: void methodA() {} };
class B { public: void methodB() {} };
class C : public A, public B {};
C obj;
obj.methodA();
obj.methodB();
C# 인터페이스 대체:
interface IA { void MethodA(); }
interface IB { void MethodB(); }
class C : IA, IB {
public void MethodA() { Console.WriteLine("MethodA"); }
public void MethodB() { Console.WriteLine("MethodB"); }
}
이름짓기 어렵겠는걸!
짖다(개)
짖다(개1)
짖다(고양이1)
짖다(고양이2)
// C++에서 함수 오버로딩
#include <iostream>
using namespace std;
void print(int num) {
cout << "Number: " << num << endl;
}
void print(double num) {
cout << "Double: " << num << endl;
}
int main() {
print(10); // 정수 출력
print(3.14); // 실수 출력
return 0;
}
C, C++ 자바에 비해 개발자가 메모리까지 관리해야한다니! 정말 아는게 많아야 한다!
예시: 동적 메모리 할당
// C 코드
int* arr = (int*)malloc(10 * sizeof(int)); // 타입 캐스팅 필요
free(arr);
// C++ 코드
int* arr = new int[10]; // 타입 캐스팅 필요 없음
delete[] arr;

그래서 나온게 C# 자바처럼 가비지 콜렉터가 메모리를 자동으로 해제해준다
예시: C++ STL 사용
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> numbers = {1, 2, 3};
numbers.push_back(4); // 동적으로 데이터 추가
for (int n : numbers) {
cout << n << " ";
}
return 0;
}

C++ STL 벡터:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> numbers = {1, 2, 3};
numbers.push_back(4);
for (int n : numbers) {
cout << n << " ";
}
return 0;
}
C# 리스트:
using System;
using System.Collections.Generic;
class Program {
static void Main() {
List<int> numbers = new List<int> { 1, 2, 3 };
numbers.Add(4);
foreach (int n in numbers) {
Console.Write(n + " ");
}
}
}
C#에는 collection이 있다고?! 이건 java아닌가?!
collection 라이브러리로 인해 다형성이 강화되었다! 다양한 타입을 같은 함수로 순회가 가능해진다!
C언어 예외처리도 없었던거냐???
C++ 예외 처리:
#include <iostream>
using namespace std;
int main() {
try {
throw "An error occurred"; // 예외 발생
} catch (const char* e) {
cout << e << endl; // 예외 처리
}
return 0;
}
C# 예외 처리:
using System;
class Program {
static void Main() {
try {
throw new Exception("An error occurred");
} catch (Exception ex) {
Console.WriteLine(ex.Message);
} finally {
Console.WriteLine("Cleanup code runs here.");
}
}
}
C 예외 처리:
// 1. 조건문을 활용한 간단한 예외 처리
// C에서는 함수에서 에러 발생 시 반환 값을 이용해 예외 처리를 흉내 낼 수 있습니다.
// 예시: 숫자를 0으로 나누는 경우 처리
#include <stdio.h>
// 함수 선언
int divide(int numerator, int denominator);
int main() {
int a = 10, b = 0;
int result = divide(a, b);
if (result == -1) {
printf("에러: 0으로 나눌 수 없습니다.\n");
} else {
printf("결과: %d\n", result);
}
return 0;
}
// 나눗셈 함수
int divide(int numerator, int denominator) {
if (denominator == 0) {
return -1; // 오류 코드 반환
}
return numerator / denominator;
}
// 2. 함수 포인터와 콜백을 이용한 예외 처리
// C에서는 함수 포인터를 이용해 오류 발생 시 특정 동작을 수행하도록 설정할 수 있습니다.
// 예시: 콜백 함수로 예외 처리
#include <stdio.h>
void onError(const char* errorMessage) {
printf("에러 발생: %s\n", errorMessage);
}
int divide(int numerator, int denominator, void (*errorCallback)(const char*)) {
if (denominator == 0) {
errorCallback("0으로 나눌 수 없습니다.");
return -1; // 오류 코드 반환
}
return numerator / denominator;
}
int main() {
int a = 10, b = 0;
int result = divide(a, b, onError);
if (result != -1) {
printf("결과: %d\n", result);
}
return 0;
}
//3. setjmp와 longjmp를 이용한 예외 처리
// C 표준 라이브러리의 <setjmp.h>를 사용하면 예외 처리를 흉내 낼 수 있습니다.
// setjmp는 현재의 실행 상태를 저장하고, longjmp는 저장된 상태로 다시 돌아가 실행을 계속합니다.
//예시: 0으로 나누는 경우 예외 처리
#include <stdio.h>
#include <setjmp.h>
jmp_buf jumpBuffer; // 예외 발생 시 되돌아갈 위치 저장
void divide(int numerator, int denominator) {
if (denominator == 0) {
printf("에러: 0으로 나눌 수 없습니다.\n");
longjmp(jumpBuffer, 1); // 예외 발생 시 setjmp로 되돌아감
}
printf("결과: %d\n", numerator / denominator);
}
int main() {
if (setjmp(jumpBuffer) == 0) {
// 정상 실행
divide(10, 2); // 정상 실행
divide(10, 0); // 예외 발생
} else {
// longjmp로 복귀했을 때 실행
printf("예외 처리 완료.\n");
}
return 0;
}
//4. 사용자 정의 매크로를 이용한 예외 처리
//매크로와 goto를 조합하여 간단한 예외 처리를 구현할 수 있습니다.
//예시: 매크로로 예외 처리
#include <stdio.h>
#define THROW_ERROR(msg) do { printf("에러: %s\n", msg); goto error; } while (0)
int main() {
int a = 10, b = 0;
if (b == 0) {
THROW_ERROR("0으로 나눌 수 없습니다.");
}
printf("결과: %d\n", a / b);
return 0;
error:
printf("예외 처리 완료.\n");
return -1;
}
아 그래서 게임에서 c++을 사용하는 이유가, 메모리를 커스텀하기 위함과 동시에 자바처럼 oop를 사용하기 위해 c++를 사용하기 위함이군!
둘다 게임에 적합!
성능이 중요해? C++
개발자가 편하게? C#
C#은 성능은 낮췄지만, 편의성에 초점을 맞춘다