C++에서 Reference란 참조자라고 하여, 변수 자체가 아닌

변수를 가리키는 또다른 별명이라고 할 수 있다.

예를 들어 int형 변수 a가 있다고 할 때,

int &b = a 로 선언하고 b 값을 변경하면 실제 a의 값도 같이 바뀐다.


그래서 보통 swap 함수를 만들 때, 포인터로 넘겨주고 값을 변경하기도 귀찮고 하기 때문에 레퍼런스를 자주 사용한다.



1
2
3
4
5
void swap(int& a, int& b) {
    int tmp = a;
    a = b;
    b = tmp;
}
cs


처럼 말이다.

이렇게 변수로 함수의 인자를 받지 않고 레퍼런스로 받는 것을 Call-by-reference라고 한다.

(변수로 받는 것은 Call-by-value 라고 한다)


메모리를 공부했다면 여기서 어떻게 이게 되는지 신기할 수 있다.

포인터로 받아서 참조해서 값을 변경해준다고 하면 이해가 되겠지만, 레퍼런스로 받아서 값을 변조시키는 것은

그냥 봤을 때는 32비트 기준으로 EBP+8 주소의 값을 바꾸는 것과 같은 행동으로 보이기 때문에, 원본의 값과는 아무런 상관이 없어 보인다.

그래서 직접 디스어셈블링해서 구조를 확인해 봤다.




코드는 위와 같다.

간단하게 main에 a라는 int형 변수를 하나 선언하고 한번 출력한 다음,

이를 func에 Call-by-reference로 넘겨 값을 변경시킨 후 다시 출력하는 소스이다.



컴파일을 마치고 실행시켜 보면 의도했던 대로 a의 값이 변경되어 있는 것을 볼 수 있다.



그리고 gdb로 디스어셈블하여 내부를 살펴 보면, 나는 하지도 않았는데 자동으로 포인터 연산을 통해 값을 넣는 것이 보인다.

EBP+8에는 실제로 a의 주소가 들어 있었고, 이 주소를 참조하여 10을 넣어 준 것이다.

코드에서 내가 직접 짜주지는 않았지만, 컴파일러가 이렇게 되도록 컴파일한것이다.



이렇게 보고 나니 또 레퍼런스가 참조하는 변수를 바꿀 수는 없는가에 대한 생각이 들었다.

구글링해가면서 살펴보니 가능하기는 하더라.




이런식으로, functional을 include한 뒤, std::ref에 해당 변수를 넣어서 레퍼런스를 바꿔줄 수 있다.

저 std::ref같은 경우 'std::reference_wrapper' 타입을 리턴하기 때문에 쓰기 귀찮으니 auto를 쓰는게 편하다.

딱 봐도 레퍼런스를 변조하려고 하니 코드가 좀 복잡해졌다.

실제로 컴파일하고 실행시켜 보면,


(g++로 컴파일하려고 하니 -std=c++11 옵션을 줘야 하더라)


의도한 대로 값이 변경된 것을 알 수 있다.


이것도 로우레벨로 내려가서 좀 더 분석해보자.


(히익 이게 뭐야 무서워)


C++ 특성상 컴파일하고 나니 심볼이 엄청 더럽게 바뀌었다.

이래서 C++ 리버싱하는게 정말 싫은 것이다.


보아하니 EBP-0x20에 a 변수가 존재하고, EBP-0x24에 b 변수가 존재한다.

lea 명령으로 EBP-0x28의 주소를 edx에 넣고, EBP-0x20의 주소를 eax에 넣은 후,

push edx와 push eax를 수행한다.

이후 call하는걸 보니 std::ref의 첫 번째 인자로 &c, 두 번째 인자로 &a가 들어갔다.

이후 ostream이 나올 때까지 딱히 변화가 없는 것을 보아, 여기에서 c에는 이미 std::ref(a)가 들어갔음을 알 수 있다.

출력 이후, 맨 밑을 보면 c.get()이 실행되어 그곳에 포인터로 0xa를 넣는 것이 보인다.



아랫부분을 보니 또 이렇게 ebp-0x24 주소를 인자로 넘기고,

또 ebp-0x28 주소도 인자로 넘기는데, call을 여러번 수행한다.

아무래도 std::ref(b)를 수행한 뒤, 연산자 오버로딩 된 '='을 이용해 넣는 부분인 것 같다.

잘렸지만 이 부분 다음에 c.get()을 수행하고 0x14를 mov하는 부분도 있다.


결국 결론을 내리면 레퍼런스는 컴파일러딴에서 알아서 잘 포인터로 처리해 준다는 것.

우리는 그냥 실제 변수가 있는 것처럼 쓰기만 하면 된다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

보통 네트워크 통신을 진행할 때, NAT를 이용하여 공인IP를 사설IP로 나눠서 사용하곤 한다.
(A
클래스에서는 10.~, B클래스에서는 172.16.~, C클래스에서는 192.168.~ 등으로 나뉘는, 그 주소이다.)

OSI 7계층이라는 말을 많이 들어 보았을 것이라고 생각한다.
OSI 7
계층은 통신 계층을 수직적으로 7개의 각각 다른 계층으로 나누어 놓은 것으로,
각 계층을 독립적으로 구성하여 변경이 필요할 시 해당 모듈만을 변경해도 되도록 만든 것이다.


OSI 7계층은 낮은 순서대로 물리데이터 링크네트워크전송세션표현응용 계층으로 구성된다.

OSI 7계층을 좀더 기능별로 압축하여 만든 TCP/IP 계층 구조도 있는데,
이는 낮은 순서대로 네트워크 인터페이스인터넷전송응용 계층으로 구성된다.


TCP로 데이터를 전송하는 통신을 할 때, OSI 7계층 기준으로 세션/표현/응용 계층에 Data가 전달되고
전송 계층의 대표적인 프로토콜인 TCP에 해당 어플리케이션의 Port TCP 통신에 필요한 정보들이 지정되며,
네트워크 계층의 대표적인 프로토콜인 IP에 말 그대로 IP 주소가 지정된다.


한 단계 더 내려가 네트워크 인터페이스 계층까지 내려가 보면 실질적인 통신을 위한 MAC Address 네트워크 계층에서 사용하는 프로토콜에 대한 정보 등을 담고 있다.
그 밑인 물리 계층은 캡슐화 종류, 전체 패킷의 길이 등을 담고 있다.

이해를 돕기 위해 계층의 중요한 저장되는 정보를 연결하여 나타내면 다음과 같다.


세션/표현/응용 : Data
전송 : Dest_port, Src_port
네트워크 : Dest_ip, Src_ip
데이터 링크 : Dest_MAC, Src_MAC


네트워크의 통신에 대해 생각하는 도중, 의문이 든 것이 바로 이 부분이었다.

사설망 내부에서 내 PC가 서버로 보낸 패킷은 네트워크 계층에 다음과 같은 정보가 담겨서 나간다.
네트워크 : Src_ip = “192.168.0.6”, Dest_ip = “8.8.8.8”
이는 와이어샤크로 직접 확인해 봤을 때도 나타난 결과이다.





그런데 우리는 당연하게 생각하고 있는 것이,
우리는 사설 네트워크 내부에 있는데 바깥의 서버와 통신을 할 때는 공인IP를 이용한다는 것이다.
내 패킷이 저대로 전달된다고 가정하면 “8.8.8.8”에서는 내 패킷을 받고, Src_ip “192.168.0.6”였으므로 당연히 저 주소로 Response를 하게 되는데, 조금만 생각해도 될 리가 없다. 사설 네트워크의 주소이기 때문이다.


“8.8.8.8”
과의 통신을 위해서는 사설 네트워크의 주소가 아닌 공인IP를 이용하여 통신해야 한다.

그런데 패킷 구조 어디를 봐도 공인IP로 통신을 하기 위해 공인IP를 저장하는 공간이 없다.

라우터 측에서 네트워크계층의 src_ip 부분을 공인IP로 변경한다고 가정할 수도 있는데, 이렇게 되면 Response 패킷의 dest_ip 부분이 공인IP 주소로 바뀌어야 한다.


하지만 실제로 들어온 패킷을 wireshark를 이용해 잡아본 결과,
dest_ip
에는 사설 네트워크 내부의 내 IP 주소가 들어있다.

이게 가능하기 위해서는 패킷이 PC를 떠나 라우터를 거쳐 서버로 향하는 과정에 라우터의 공인IP 주소를 담는 부분이 패킷에 추가되어야 한다.


또는 다른 방식을 이용하여 어떻게든 공인IP와 사설IP를 모두 저장할 방법이 필요하다.

그런데, 직접 서버에서 사설망 내부에서부터 보내진 패킷을 잡아서 분석해 봤더니

이렇게, 공인IP 주소가 찍혀 있는 것을 볼 수 있었다.


마찬가지로 Response 패킷을 확인해 보니

Dest_ip에 공인IP 주소가 적혀 있다.

이를 통해 내가 보낸 패킷이나 내가 받는 패킷은 라우터를 기점으로 네트워크계층의 프로토콜에 변동이 일어나고,


사설망->외부망 : 사설IP->공인IP

외부망->사설망 : 공인IP->사설IP


형식으로 바뀐다는 것을 알 수 있었다.

그럼 대체 이건 어떻게 작동하는 것일까.
그나마 예측하자면 라우터에 통신 내역이 저장되거나, MAC Address를 보고 거기에 맞춰 IP Address를 넣어주던가, 두가지 가능성이 있는데,
후자같은 경우 데이터 링크 계층의 MAC Address같은 경우 통신의 주체가 바뀔 때마다 바뀌어버리기 때문에 불가능하다.
따라서 전자라는 의미인데, 과연 라우터 내부에서 어떻게 저런 일이 가능한지가 궁금하다.


이 부분은 나중에 더 공부하도록 하자.


공부해서 알아낸 내용을 정리하였다.


'Knowledge' 카테고리의 다른 글

RC4 Stream Cipher  (0) 2016.07.19
스트림 암호 (Stream Cipher)  (0) 2016.07.18
Greedy Algorithm + 회의실 배정  (0) 2016.06.21
Kernel/User mode  (0) 2016.04.15
마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



내가 아주 좋아하고 자주 사용하는 C++ 오픈소스 라이브러리인 libtins의 소스 코드 일부이다


분명히 const resource 레퍼런스 타입으로 변수를 받고, 변수명은 resource.

타입명과 변수명이 같아도 되는걸까...

실행 자체는 잘 되는데 또 이 함수를 직접 이용하려고 하니까 왠지 안되더라.

실제로 IDE에서 저 파일 내부의 소스를 살펴보니 cannot resolve가 뜨는데, 사용 안하고 돌린 코드는 또 잘돌아가니 미칠 지경

으으 어떻게 고쳐야 하지...

'잡담' 카테고리의 다른 글

Todo List  (0) 2016.07.18
이스트소프트 면접 후기  (4) 2016.07.06
ESTSOFT 코딩테스트 합격  (1) 2016.06.29
ESTSOFT 코딩테스트 후기  (19) 2016.06.27
문제파악과 영어능력은 중요하다  (0) 2016.06.24
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


1차 서류 통과 이후 걱정했던 코딩테스트를 통과했습니다.

이제 실무진 면접과 최종면접만 남았네요.


어떤 질문이 나올 지 몰라 매우 걱정되기는 하지만 최대한 준비하고 공부하며 기다리겠습니다.

1대 다 면접이라 압박이 엄청 심할 것 같은데...

꼭 합격했으면 좋겠네요 :D

'잡담' 카테고리의 다른 글

이스트소프트 면접 후기  (4) 2016.07.06
소스가 왜 돌아가는지 신기하다  (0) 2016.06.30
ESTSOFT 코딩테스트 후기  (19) 2016.06.27
문제파악과 영어능력은 중요하다  (0) 2016.06.24
Todo List  (0) 2016.06.24
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,




 1차 서류 합격 이후, 부족한 알고리즘을 계속 공부하고 저번주 토요일에 판교역 2번출구 옆, 스타벅스에서 코딩테스트를 했다.


 학교에서 엄청 긴장하고 챙겨 나오느라 알고리즘 책이랑 여러가지 다 챙겼는데 가장 중요한 노트북 충전기를 안 챙겨와서 엄청 불안했다. 다행히도 노트북은 배터리가 100%였던 터라 5시간 이상은 쓸 수 있었고, 코딩테스트는 총 4시간동안 진행했으니 큰 무리는 없이 테스트를 진행할 수 있었다.


 이 테스트에 대해 어디까지는 이야기해도 되고, 어디부터는 하면 안 되는지를 잘 모르겠다.

그래서 문제 내용이나 주제에 대한 언급은 일절 하지 않고 후기만 쓰도록 하겠다.



 일단 문제를 풀면서 느낀 것은, 역시 '특성화고 졸업예정자'로 넣었다 보니 심각하게 어려운 문제까지 나오지는 않았다는 것이다.

경력자나 학사 이상에 지원했으면 훨씬 어렵고 복잡한 문제가 나왔겠지만, 문제의 대부분은 짧은 코드와 간단한 생각만으로도 풀 수 있었다.


 하지만 마지막 한 문제가 발목을 잡았고, 결국 시간의 70% 정도를 마지막 문제를 푸는 데에 사용했다. 시간복잡도와 공간복잡도를 생각해가면서 알고리즘을 작성하고, 이를 적용해서 코드를 짜야 하다 보니 힘들긴 했지만, 예상했던 것만큼 크게 어렵지는 않았다. 서류합격 이후 계속 영어로 된 알고리즘 문제를 푸는 연습을 한 덕분인 것 같다.


 문제를 풀면서 가장 크게 느낀 것은 (기본적이게도) 인간의 뇌는 당분 없이는 제대로 된 사고를 할 수 없다는 것이다. 아침에 밥을 먹지 않고 대충 끼니를 때운 후, 스타벅스에서 아메리카노나 시켜서 마시고 하다 보니 카페인이 들어오고 머릿속에서는 알고리즘을 계속 생각하고 있고 긴장까지 해서 당분이 급속도로 소모되었다.

 한 두시간쯤 지나고, 마지막 문제에 매달리고 있는데 당이 부족하니까 간단한 생각조차도 너무 시간이 오래 소요되고, 집중도 되지 않았다. 위기의식을 느끼고 겨우 카페모카에 휘핑크림 잔뜩 얹어서 마시고 나서 문제를 풀었다. 시험 칠때 밥은 꼭 먹고 하도록 하자...


만약 이 테스트를 통과한다면 앞으로 면접이 두 번 남고,

그 면접까지 통과하고 나야 입사할 수 있게 된다.

꼭 붙었으면 좋겠다. :)



* 문제 관련해서 질문이 많아 본문에 작성해둡니다.

 저의 경우 메일로 코딩테스트를 진행할 URL이 전달되었고, 지정된 제한 시간 전까지 들어가서 4시간동안 문제를 풀면 되었습니다. URL 전달 후부터 제한 시간까지는 상당히 넉넉하니 걱정하지 않으셔도 됩니다. 홈페이지 입사 공지사항에도 나와있는 내용이지만, 코딩테스트는 codility라는 곳을 이용하여 온라인으로 진행합니다. (관련내용 : https://estsoft.recruiter.co.kr/bbs/appsite/notice/read/69162)

실제 이 사이트에서 제공하는 레슨과 챌린지와 비슷한 방식으로 진행되므로 코딩테스트 준비중이시라면 꼭 들어가셔서 문제를 풀어보시는게 좋겠습니다. (https://app.codility.com/programmers/lessons/1-iterations/ )

'잡담' 카테고리의 다른 글

소스가 왜 돌아가는지 신기하다  (0) 2016.06.30
ESTSOFT 코딩테스트 합격  (1) 2016.06.29
문제파악과 영어능력은 중요하다  (0) 2016.06.24
Todo List  (0) 2016.06.24
갈수록 시간복잡도가 중요해지네  (0) 2016.06.18
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


Codility에서  Dynamic Programming 문제를 푸는 도중,

set 이라는 것을 무심코 넘겼다가 피 보는 일이 생겼다.

set {-1, 1} 이면 한 집합이고, 이 안에 들어 있는 원소를 임의로 사용할 수 있는 것인데,

나는 이 집합이 배열의 일부이고, {-1. 1}이 반복되는 배열이라 내가 건드릴 수 없는 영역이라 판단했다.


또한 식을 살펴보면 배열의 모든 원소를 더하는 소스인데도 일부만 더할 수 있다고 마음대로 판단해 버렸다.

문제가 무엇인지 제대로 파악하는 능력, 모의고사같은 실력을 평가하는 영어 실력 뿐만이 아닌 실용적인 영어 실력(set=집합 등)을

기를 필요성이 있어 보인다.


많이 풀어보도록 하자.

일단 짠 소스는 아까우니까 올려두도록 하겠다.


임의의 길이의 vector<int> A가 주어질 때, 이 배열에 {-1. 1. -1, 1...} 을 곱하고,

부분합의 절댓값의 최소값을 구하는 소스는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <math.h>
 
int solution(vector<int> &A) {
    if (A.size() == 0return 0;
    vector<int> psum;
    psum.push_back(0);
    int sum = 0;
    for (int i = 0; i<A.size(); i++) {
        sum += A[i] * ((i % 2) ? -1 : 1);
        psum.push_back(sum);
    }
 
    int minSum = abs(psum[1]);
    for (int i = 2; i <= A.size(); i++) {
        for (int j = 0; j < i; j++) {
            if (minSum > abs(psum[i] - psum[j])) minSum = abs(psum[i] - psum[j]);
        }
    }
    return minSum;
}
cs


'잡담' 카테고리의 다른 글

ESTSOFT 코딩테스트 합격  (1) 2016.06.29
ESTSOFT 코딩테스트 후기  (19) 2016.06.27
Todo List  (0) 2016.06.24
갈수록 시간복잡도가 중요해지네  (0) 2016.06.18
학교 다니면서 다 한다는게 힘들긴 하구나  (0) 2016.06.17
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

Todo List

2016. 6. 24. 09:35

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.



Greedy Algorithm



그리디 알고리즘이란 문제의 해를 구하는 데에 있어 매 순간에 최적의 값을 택하는 알고리즘이다.

모든 경우의 수를 전부 체크하지 않기 때문에 이 알고리즘을 통해 최적의 경우를 찾았다고 확신할 수는 없다.

따라서 이 알고리즘을 사용할 때에는 실제로 이 알고리즘이 전체 경우의 수를 고려했을 때에도

최적의 결과를 낼 수 있는지를 꼭 고려해 봐야 한다.



다음은 정올 1370번 문제인 회의실 배정(http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=645&sca=3020)의 풀이를 직접 작성한 것이다.

이 경우, 이전 회의가 끝나지 않으면 다음 회의가 진행될 수 없다는 제약 조건을 이용하여

모든 회의의 종료 시각을 기준으로 오름차순 정렬하고, for문을 이용해 모든 조건을 다 돌면서

다음 회의의 시작 시각이 현재 회의의 종료 시각보다 작은 경우에 값을 저장하고, 나머지는 무시해버리면 된다.

어차피 오름차순으로 정렬되어 있기 때문에 시작 시간이 같은 경우 가장 빨리 끝나는 회의가 가장 앞에 위치한다.



...라는 목적으로 작성한 코드인데, 왜인지 잘 작동하지 않는다.

내 컴퓨터에서는 정상적으로 작동하고 값도 잘 나오는데, 정올에 돌리니 Runtime Error가 나더라...

나중에 확실히 성공하게 되면 수정하도록 하겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
 
using namespace std;
 
bool mySortASC(pair<intpair<intint>> i, pair<intpair<intint>> j) {
    return i.second.second < j.second.second;
}
 
int main(int argc, char *argv)
{
    vector<pair<intpair<intint>>> meet;
    vector<int> ret;
    int num, startHour, endHour, N;
    int minTime = 2147483647;
 
    cin >> N;
    for (int i = 0; i<N; i++) {
        cin >> num;
        cin >> startHour;
        cin >> endHour;
        meet.push_back(pair <intpair<intint>>(num, pair<intint>(startHour, endHour)));
    }
 
    sort(meet.begin(), meet.end(), mySortASC);
    ret.push_back(meet[0].first);
    endHour = meet[0].second.second;
    for (int i = 1; i < N; i++) {
        if (endHour <= meet[i].second.first) {
            endHour = meet[i].second.second;
            ret.push_back(meet[i].first);
        }
    }
    
    cout << ret.size() << endl;
    for (int i = 0; i < ret.size(); i++) {
        cout << ret[i] << " ";
    }
    cout << endl;
 
    system("pause");
    return 0;
}
cs


'Knowledge' 카테고리의 다른 글

스트림 암호 (Stream Cipher)  (0) 2016.07.18
사설망-외부망 통신에 대한 공부  (0) 2016.07.02
Kernel/User mode  (0) 2016.04.15
마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
libcapstone-dev 설치 방법  (0) 2016.03.12
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



코드를 엄청 간단하게 짤려고 그냥 막 for문같은거 남발하면 시간복잡도가 막 O(N**2)가 되어버리고 그런다


으아아 얼른 줄여야지!

'잡담' 카테고리의 다른 글

문제파악과 영어능력은 중요하다  (0) 2016.06.24
Todo List  (0) 2016.06.24
학교 다니면서 다 한다는게 힘들긴 하구나  (0) 2016.06.17
알고리즘이 생각했던 것보다 중요하구나  (0) 2016.06.07
Todo List  (0) 2016.06.07
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

https://github.com/skyclad0x7b7/WLAN-Crack


 C++과 libtins를 이용하여 ARP Spoofing을 이용한 MITM 공격에 성공하였다.


 헤더파일로 나눠서 클래스화했고, 나중에 더 많은 기능을 추가하던지 해서 무선 랜 해킹 라이브러리를 만들어 볼 생각이다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,