반응형

해당 글은 아래 posting으로 이전함

https://m.blog.naver.com/younjung1996/223364514538

 

[BLE 실내 측위 프로젝트] Indoor Positioning System 포스팅 리스트

BLE 실내 측위 프로젝트 1. Flutter_blue 설정 (feat.안드로이드12 권한 이슈) : https://m.blog.naver...

blog.naver.com

BLE 실내 측위 프로젝트

1. Flutter_blue 설정 (feat.안드로이드12 권한 이슈) : https://m.blog.naver.com/younjung1996/223334840714

2. Bluetooth Low Energy(BLE) 통신 스케줄, 안드로이드 함께 이해하기 : https://m.blog.naver.com/younjung1996/223357207874

3. Flutter BLE Scan Demo Program, RSSI monitoring : https://m.blog.naver.com/younjung1996/223357242785

4. BLE advertising packet 기본 구성 : https://m.blog.naver.com/younjung1996/223363785615

5. BLE Beacon의 RSSI 값에서 거리를 계산하는 방법 (feat.log distance path loss model) : https://m.blog.naver.com/younjung1996/223363790198

6. RSSI 변동을 해결하기 위한 이동 평균 필터 : https://m.blog.naver.com/younjung1996/223363794361

7. NRF51822 비콘 테스트 및 초기 설정 : https://m.blog.naver.com/younjung1996/223363798262

8. Flutter 좌표 그리기 (데카르트 좌표계) : https://m.blog.naver.com/younjung1996/223363801930

9. Flutter 좌표에 실시간으로 원 그리기 : https://m.blog.naver.com/younjung1996/223363804574

10. 삼변측량 정리 및 구현 : https://m.blog.naver.com/younjung1996/223363808851

11. Flutter BLE indoor position(실내 위치 추적) system demo, 실내 네비게이션 : https://m.blog.naver.com/younjung1996/223364500752

 

관련 이슈 & 디버깅

1. [Debug] Dart matrix2d Transpose debuging, "'double' is not a subtype of type 'int'" : https://m.blog.naver.com/younjung1996/223367275545

728x90
반응형
반응형

Call by Value 와 Call by Reference 의 차이에 대해 이야기합니다. 

 

아래 하나의 예제를 보겠습니다.

#include <stdio.h>


void call_by_value(int test)
{
	test = test + 10;
	printf("call by value address %p\n", &test);
}

int call_by_value_return(int test)
{
	test = test + 10;
	printf("call by value address %p\n", &test);
	return test;
}

void call_by_reference(int *test)
{
	printf("call by reference %p\n", test);
	*test = *test+1;
}


int main()
{
	int value = 10;

	printf("val %d\n", value);
	printf("val address %p\n", &value);

	printf("-------------------------\n");
	call_by_value(value);
	printf("val %d\n", value);
	printf("val address %p\n", &value);

	printf("-------------------------\n");
	call_by_reference(&value);
	printf("val %d\n", value);
	printf("val address %p\n", &value);

	printf("-------------------------\n");
	int value_return = call_by_value_return(value);
	printf("val %d\n", value);
	printf("val address %p\n", &value);
	printf("val_return %d\n", value_return);
	printf("val_return address %p\n", &value_return);

	return 0; 
}

아래 간단한 C코드의 결과이다.

위 결과가 위 처럼 나온 것을 이해하기 위해선 메모리에 대한 고민이 필요합니다.

 

우선, 메모리에는 컴파일 전 메모리를 할당하는 데이터 영역과 스택(Stack)영역과 힙(Heap)영역이 있습니다. 

  • 데이터(Data) 영역 (정적 메모리)
    • 전역 변수와 static 변수가 할당되는 영역
    • 프로그램의 시작과 동시에 할당되고 프로그램이 종료되어야 메모리에서 소멸됨
  • 스택(Stack) 영역
    • 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역
    • 함수 호출이 완료되면 사라짐
  • 힙(Heap) 영역
    • 동적으로 할당된 변수

데이터 영역과 힙 영역은 사용되고 있지 않습니다.

스택 영역의 현재 코드를 그림으로 간단히 나타내면,

 

위 코드 메모리를 간단한 블록 그림으로 나타냄

스택영역은 컴파일하면서 Stack영역을 위 사진 같이 메모리를 할당합니다.

 

Call by Value는 Main 함수에서 다른 함수로 인자의 을 전달하기 때문에, Main 함수의 인자와 다른 함수의 인자는 서로 다른 주소를 가집니다. 그렇기 때문에 다른 함수에서 인자 값이 변하더라도 Main 함수의 인자는 다른 변수이기 때문에 아무 일도 일어나지 않습니다. 

 

Call by Reference는 Main 함수에서 다른 함수로 인자의 주소 값을 전달하기 때문에, Main 함수의 인자와 다른 함수의 인자는 서로 같은 주소를 가집니다. 그렇기 때문에 다른 함수에서 값이 인자 값이 변하더라도 Main 함수의 인자는 같은 변수 이기 때문에 변하게 됩니다.

728x90
반응형
반응형

 

 

안녕하세요. 오늘은 UNION과 STRUCT에 대해 이야기 하겠습니다. 

 

coding-yoon.tistory.com/119

 

[C] 구조체 포인터 접근과 최적화

요즘 기본기가 중요함을 느끼고 C를 공부하고 있습니다. 1. 구조체 단순히접근 #include //Struct packet 선언 typedef struct packet { int data0; int data1; int data2; }Packet; int main() { Packet p; //Str..

coding-yoon.tistory.com

구조체에 대한 이야기는 위에 작성했지만, 저보다 훨씬 자세히 적은 블로그 분들이 많기 때문에 따로 찾아보시길 바랍니다.

 

UNION의 구조를 먼저 알아보겠습니다. 

 

UNION은 가장 사이즈가 큰 변수와 메모리를 공유합니다.

 

이게 무슨 말인가 하면

#include <stdio.h>

// 공용체 선언
typedef union data
{
	char a; 
	char b; 
	char c[2]; 
}Data;

int main(){

	Data data; // 공용체 data 정의

	data.c[0] = 'a';
	data.c[1] = 'b';

	printf("data.a = %c\n", data.a);
	printf("data.b = %c\n", data.b);
	printf("data.c[0] = %c\n", data.c[0]);
	printf("data.c[1] = %c", data.c[1]);
	

	return 0;
}


 

이런 간단한 코드에서  결과는 어떻게 나올까요?

 

왜 이런 결과가 나오느냐. 그림을 보시면 바로 이해할 수 있습니다.

 

이런 구조로 메모리를 서로 공유하고 있습니다. 주소를 찍어보면 더 확실하게 알 수 있습니다. 

 

#include <stdio.h>


typedef union data
{
	char a; 
	char b; 
	char c[2]; 
}Data;

int main(){

	Data data; 

	data.c[0] = 'a';
	data.c[1] = 'b';

	printf("data.a = %p\n", &data.a);  // a 주소 출력
	printf("data.b = %p\n", &data.b);  // b 주소 출력
	printf("data.c[0] = %p\n", &data.c[0]);  // c[0] 주소 출력
	printf("data.c[1] = %p", &data.c[1]);  // c[1] 주소 출력
	

	return 0;
}


출력

Union의 사이즈는 가장 사이즈가 큰 변수이며, 메모리를 공유합니다. 

 

Union은 어디에 많이 쓰일까요? 대표적으로 통신 분야로 가장 많이 사용됩니다. 

 

통신에서는 데이터를 전송을 잘하는 것도 중요하지만, 데이터를 수신해서 제대로 분해하는 것도 굉장히 중요합니다. 

 

꼭 이렇게 사용한다는 아니지만, 구조체와 적절히 사용하면 송신부분 수신부분을 만들 수 있습니다.  

 

#include <stdio.h>
#include <stdint.h>


// Struct Packet_s 선언
typedef struct packet_s
{
	uint8_t data0;
	uint8_t data1;
	uint8_t data2;
	uint8_t data3;

}Packet_s;

typedef union packet_u
{
	Packet_s ps;  // Struct Packet_s ps 정의 // 송신
	uint8_t pu[4];  // 수신
}Packet_u;



int main()
{
	Packet_u packet_data;

	packet_data.ps.data0 = 0;  // 예를 들어 uuid
	packet_data.ps.data1 = 1;  // minor
	packet_data.ps.data2 = 2;  // tx power
	packet_data.ps.data3 = 3;  // rssi

	printf("pacekt_data size = %d bytes\n\n", sizeof(packet_data));

	printf("송신 사이즈 : %d bytes\n\n", sizeof(packet_data.ps));

	
	printf("------송신 준비 완료------\n");
	printf("--------------------------\n");
	printf("--------------------------\n");
	printf("-------송수신 완료--------\n\n");

	printf("수신 사이즈 : %d bytes\n", sizeof(packet_data.pu));
	printf("uuid = %d\n", packet_data.pu[0]);
	printf("minor = %d\n", packet_data.pu[1]);
	printf("tx power = %d\n", packet_data.pu[2]);
	printf("rssi = %d\n", packet_data.pu[3]);


	

	return 0;
}

 

 

이런식으로 재밌게 구조체와 공용체를 관계를 적절히 사용하여 통신 패킷을 만들어 보았습니다.

 

그 외에도 Union은 다양한 방법으로도 유용하게 사용되고 있습니다. 

728x90
반응형
반응형

요즘 기본기가 중요함을 느끼고 C를 공부하고 있습니다. 

 

 

1. 구조체 단순히접근

#include <stdio.h>

//Struct packet 선언
typedef struct packet
{
	int data0;
	int data1;
	int data2;

}Packet;

int main()
{
	Packet p;  //Struct Packet 정의

	p.data0 = 0;
	p.data1 = 1;
	p.data2 = 2;

	printf("%d %d %d ", p.data0, p.data1, p.data2);
	return 0;
}

 

 

 

 

 

2. 구조체 포인터로 접근

#include <stdio.h>


// Struct packet 선언
typedef struct packet
{
	int data0;
	int data1;
	int data2;

}Packet;



int main()
{
	Packet p;  // Struct Packet 정의
	Packet* p_pointer;  // Packet에 대한 Pointer 선언 
	p_pointer = &p;  // Pointer 정의 

	p_pointer->data0 = 0;
	p_pointer->data1 = 1;
	p_pointer->data2 = 2;

	printf("%d %d %d ", p.data0, p.data1, p.data2);
	return 0;
}

 

 

 

 

 

3. Struct 최적화 (Padding bit)

#include <stdio.h>


// Struct packet 선언
typedef struct packet
{
	char data0;
	char data1;
	int data2;

}Packet;



int main()
{
	Packet p;  // Struct Packet 정의

	printf("%d", sizeof(p));

	return 0;
}

 

과연 위 구제체는 몇 비트인가?

 

6바이트라고 생각할 수 있지만, 8바이트

 

이유 : 구조체는 가장 큰 변수만큼 증가하기 때문이다. 

 

그렇다면 둘의 순서가 바뀌면 어떻게 되는가?

 

#include <stdio.h>


// Struct packet 선언
typedef struct packet
{
	int data0;
	char data1;
	char data2;
	

}Packet;



int main()
{
	Packet p;  // Struct Packet 정의

	printf("%d", sizeof(p));

	return 0;
}

 

똑같이 8바이트이다.

 

그렇다면 이런 구조체일 때는 몇 바이트인가?

 

#include <stdio.h>


// Struct packet 선언
typedef struct packet
{
	char data0;
	int data1;
	char data2;
	

}Packet;



int main()
{
	Packet p;  // Struct Packet 정의

	printf("%d", sizeof(p));

	return 0;
}

위 구조체는 12bytes이다.

 

극한의 메모리 낭비를 일으킨다. 

 

BLE 통신을 하게 되었는데, 통신에서는 이런 구조체와 공용체가 굉장히 중요하다. 

728x90
반응형
반응형

안녕하세요. 오랜만에 C언어에 대해 글을 써봅니다.

 

여러분들 BMP를 불러올 때 어떻게 하시나요? 

 

https://dojang.io/mod/page/view.php?id=703

 

C 언어 코딩 도장: 81.2 비트맵 구조체 작성하기

비트맵 파일의 구조를 알아보았으니 이제 비트맵 구조체를 작성합니다. 이때 주의할 점은 반드시 구조체를 1바이트 크기로 정렬해야 한다는 점입니다. 즉, 비트맵 파일에서 각 정보는 위치와 크기가 정확하게 정해져 있으므로 반드시 구조체의 크기와 형태 그대로 읽어야 합니다. #pragma pack(push, 1) // 구조체를 1바이트 크기로 정렬 typedef struct _BITMAPFILEHEADER // BMP 비트맵 파일 헤더 구조체 { unsigned

dojang.io

아마 위 본 예제가 가장 많이들 사용하실겁니다. 

 



#pragma pack(push, 1)                // 구조체를 1바이트 크기로 정렬

typedef struct _BITMAPFILEHEADER     // BMP 비트맵 파일 헤더 구조체
{
    unsigned short bfType;           // BMP 파일 매직 넘버
    unsigned int   bfSize;           // 파일 크기
    unsigned short bfReserved1;      // 예약
    unsigned short bfReserved2;      // 예약
    unsigned int   bfOffBits;        // 비트맵 데이터의 시작 위치
} BITMAPFILEHEADER;

typedef struct _BITMAPINFOHEADER     // BMP 비트맵 정보 헤더 구조체(DIB 헤더)
{
    unsigned int   biSize;           // 현재 구조체의 크기
    int            biWidth;          // 비트맵 이미지의 가로 크기
    int            biHeight;         // 비트맵 이미지의 세로 크기
    unsigned short biPlanes;         // 사용하는 색상판의 수
    unsigned short biBitCount;       // 픽셀 하나를 표현하는 비트 수
    unsigned int   biCompression;    // 압축 방식
    unsigned int   biSizeImage;      // 비트맵 이미지의 픽셀 데이터 크기
    int            biXPelsPerMeter;  // 그림의 가로 해상도(미터당 픽셀)
    int            biYPelsPerMeter;  // 그림의 세로 해상도(미터당 픽셀)
    unsigned int   biClrUsed;        // 색상 테이블에서 실제 사용되는 색상 수
    unsigned int   biClrImportant;   // 비트맵을 표현하기 위해 필요한 색상 인덱스 수
} BITMAPINFOHEADER;

typedef struct _RGBTRIPLE            // 24비트 비트맵 이미지의 픽셀 구조체
{
    unsigned char rgbtBlue;          // 파랑
    unsigned char rgbtGreen;         // 초록
    unsigned char rgbtRed;           // 빨강
} RGBTRIPLE;

#pragma pack(pop)

#pragma pack(push, 1)

 

구조체 데이터를 강제로 1바이트 단위로 쪼개서 정렬한다는 뜻입니다. 

가장 최소로 쪼개면 빈공간이 없이 정렬이 되기 때문에 메모리가 100퍼센터 사용할 수 있게 됩니다.

 

하지만 1바이트 씩 정렬하면 너무 낭비가 되지 않을까요? 

cpu가 한 번에 32bit, 64bit를 한 번에 수행하는 반면에 1바이트씩이면은... 분명 낭비가 됩니다. 그래서 많은 블로그에 

글쓰신 분들께서도  추천하지는 않습니다. 

 

오늘은 pack#pragma pack(push, 1)를 쓰지 않고 정렬하여 사용하는 방법을 알아보도록 하겠습니다.

 

 

1. BMP 바이너리 모드

BMP에 대해 알아보겠습니다. bmp를 binary mode로 열어봅시다.

 

1. visual studio

visual studio를 열어줍니다.

2. 파일 열기
3. binary mode
BMP Binary mode

파일을 열고나서 BMP인지 아닌지를 판별하는 데이터가 시작주소에서 2바이트가 존재합니다.

0x424D(16진수) => BM을 의미합니다. (bfType)

BM으로 BMP파일인지 아닌지 확인하게 됩니다. (BM이면 BMP파일) 

 

 

 

 

 

그럼 BMP파일인지 아닌지 확인해보았고.

BMP파일 구조체에 대해 알아보도록 하겠습니다.

 

1. pragma pack(push, 1)

 

2. 정렬 없음.

첫번 째 사진인 pragma pack(push,1)가 있고,

 

두번 째 사진은 pragma pack(push,1)이 없습니다.

 

첫번 째 경우는 당연히 가장 최소 단위로 쪼개기 때문에 바로 사용가능합니다.

 

하지만 두번 째 경우는 어떻게 될까요?

 

두번 째 사진을 디버깅한 결과

포인터 오류가 뜨네요. 널포인터... 아주 무서운 녀석입니다.

 

왜 이런 결과가 나올까요? 그 이유는 포인터정렬이 제대로 되지 않아 NULL 포인터가 생겼기 때문입니다.

 

구조체는 #pragma가 정의가 되어 있지 않으면 가장 큰 변수의 사이즈를 기준으로 정렬하게 됩니다.

 

2. 정렬 없음.

다시 한 번 볼까요? 가장 큰 바이트가 4바이트입니다.  그렇다면 4바이트 기준으로 정렬을 하겠네요. 

그림보시면 단박에 이해가 가실겁니다.

그림 죄송합니다 ㅜㅜ

4바이트 씩 맞춰 정렬하게 되면 이와 같이 NULL 포인터가 2바이트 발생하게 되어 저 위와 같은 오류가 뜨게 됩니다.

 

어떻게 하면 NULL 포인터를 없애면서 4바이트씩 정렬할 수 있을까요?

 

bfType을 지워버리면 됩니다.

 

요렇게요. 그렇다면 4바이트씩 정렬이 되겠죠?

이렇게요.

어? 그렇다면 bfType을 없앴는데 어떻게 bmp파일인지 아닌지 어떻게 구별하나?

 

그래서 위에 BMP파일을 바이너리 모드로 연 것입니다.

 

기억하시나요? 

 

맨 첫 주소에서 2바이트가 BM인지 아닌지 판별하는 bfType입니다. 

 

bfType이 맨 첫주소에 있기 때문에 파일 입출력 문제로 바뀌게 되는것입니다. 

 

fread로 읽어도 되지만... 파일입출력 공부겸 연습을 위해 굳이... 이렇게 써봤습니다. 

여러분들은 저 방법 말고 fread를 사용해서 읽으시길 바랍니다.~

 

아까와 똑같은 bmp파일으 열고 

 

bmp파일을 fseek함수를 이용해서 맨 첫주소로 이동하여, 0x42, 0x4D를 확인합니다. 

 

if문은 0x424D(==BM) 이면 첫 두 바이트를 출력하게 됩니다

잘 나오네요?

이 방법을 사용하면 1바이트씩이 아닌 4바이트씩 사용하여 BMP를 입출력하는 것이 가능하게 됩니다.

 

다음 C언어 글은 저 위 방법을 사용하면서, BMP를 사용해서 size를 키우는 실습(upscaling)을 해보도록 하겠습니다. 

728x90
반응형

+ Recent posts