Lecture 05_ Data Type
< Predefined Macro and Data Type >
< Define Custom Data Type (typedef) >
// Format
typedef <original data type> <new data type>
// Example
#include <stdio.h>
int main(){
typedef unsigned int unit8_t; // unit8_t == unsigned int
uint8_t A = 10;
printf("A = %u\n", A); // %u: unsigned int
return 0;
}
A = 10
< const Modifier >
< Accessing a Member in Structure in C >
- Structure
: collects one or more members into one user-defined variable
// Declaration of a structure
//structure만 describe, memory space는 아직 할당 X
struct book{
char title[20];
char author[20];
float price;
};
// Declaration of a structure variable -> 메모리 공간 확장
struct book mybook; // mybook
> Variable
: "."을 사용하여 structure variable의 member를 access
#include <stdio.h>
struct book{
char title[20]; // 20 byte
char author[20]; // 20 byte
float price; // 4 byte
};
int main(){
struct book mybook;
mybook.price = 10.0f;
printf("price = %f\n", mybook.price); // price=10.000000
return 0;
}
> Pointer
: "->"을 사용하여 structure pointer의 member를 access
: Reference operator "*"은 structure pointer variable 앞에 사용되지 않는다.
#include <stdio.h>
struct book{
char title[20]; // 20 byte
char author[20]; // 20 byte
float price; // 4 byte
};
int main(){
struct book mybook;
struct book *ptr; // 포인터
ptr = &mybook; // mybook에 할당된 주소의 위치를 포인터에 저장
ptr -> price = 10.0f; // 포인터가 위치한 곳에서 price의 위치를 가리킨다
printf("price = %f\n", ptr -> price); // price=10.000000
return 0;
}
< Memory Allocation of Structure Variable >
: Structure variable의 member는 declaration 순서에 따라 각각 할당된다.
struct book{
char title[20];
char author[20];
float price;
};
struct book mybook; // 20+20+4 = 44 bytes
< Structure Representation >
- Structure는 memory의 block을 나타낸다.
: 모든 fields를 hold할 만큼 충분히 크다.
- Fields는 선언 순서를 따른다.
- Compiler는 전반적인 size + positions of fields를 결정한다.
: Machine-level program has no understanding of the structures in the source code.
struct rec{
int a[4]; // int: 4 bytes -> 4*4 = 16 bytes
size_t i; // size_t: 8 bytes
struct rec *next; // 포인터: 8 bytes
};
< Generating Pointer to Structure Member >
- Generating Pointer to Array Element
: 포인터를 이용하여 접근한다.
> 예제 코드
- get_ap: 구조체 포인터 r, size_t 타입의 idx를 인자로 받는 함수
- 해당 배열의 특정 인덱스 요소에 접근할 수 있는 포인터를 얻게 된다.
예) get_ap(&my_rec, 2)호출 → my_rec 구조체의 a 배열에서 세 번째 요소(idx = 2)에 대한 포인터 반환
#include <stdio.h>
struct rec{
int a[4]; // int: 4 bytes -> 4*4 = 16 bytes
size_t i; // size_t: 8 bytes
struct rec *next; // 포인터: 8 bytes
};
int *get_ap (struct rec *r, size_t idx) {
return &r -> a[idx];
}
int main() {
struct rec my_rec;
my_rec.a[0] = 10;
my_rec.a[1] = 20;
my_rec.a[2] = 30;
my_rec.a[3] = 40;
int* ptr = get_ap(&my_rec, 2); // 세 번째 요소(idx=2)에 대한 포인터 얻기
printf("my_rec.a[2]의 값: %d\n", my_rec.a[2]); // 30
printf("get_ap(&my_rec, 2)로 얻은 값: %d\n", *ptr); // 30
return 0;
}
< Following Linked List >
> Following Linked List #1
> 예제 코드
- length: Linked List를 따라가면서 리스트의 길이를 반환하는 함수
1. len 변수를 초기화하여 길이를 0으로 설정한다.
2. r을 시작으로 하는 연결 리스트를 순회한다.
3. r이 NULL이 아닌 동안, len을 1 증가시키고 r을 다음 노드로 이동시킨다.
4. 리스트의 끝에 도달하면 len 변수에 저장된 길이를 반환한다.
> Following Linked List #2
> 예제 코드
- set_val: 구조체 포인터를 입력으로 받아 순회하면서 배열 a의 특정 위치에 값을 설정하는 함수
1. 함수는 입력으로 struct rec 구조체를 가리키는 포인터인 r을 받는다.
2. r을 시작으로 하는 연결 리스트를 순회한다.
3. size_t i라는 변수를 선언하고, 구조체 r의 i 멤버 값을 저장한다.
4. 구조체 r의 배열 a에서 인덱스 i에 해당하는 위치에 입력으로 주어진 val 값을 설정한다.
즉, r->a[i] = val; 이 부분은 배열 a의 i번째 요소에 val 값을 저장한다.
5. r = r->next; r을 다음 구조체를 가리키는 포인터로 업데이트하여 구조체 체인을 계속 순회한다.
→ 포인터가 가리키는 것: 위치(주소 값)
< Structures & Alignment >
1, 17은 각각 4, 8의 배수가 아니므로 padding을 넣어주어야 한다.
char: 1byte이므로 p → p+1
double: 8 byte이므로 Multiple of 8
int: 4 byte이므로 Multiple of 4
*Alignment - PC접근 1번이면 가능
< Alignment Principles >
> Aligned Data
- Primitive data type은 B bytes가 필요하다.
- Address must be multiple of B
- Required on some machines; advised on x86-64
> Motivation for Aligning Data
- Memory accessed by aligned chunks of 4 or 8 bytes (system dependent)
- datum이 2 pages (4 KB pages)에 걸쳐있을 때 Virtual memory는 더 까다롭다.
> Compiler
- structure에 gap을 삽입하여 필드가 올바르게 정렬되도록 한다.
< Specific Cases of Alignment (x86-64) >
- 1 byte: char
- no restrictions on address → 모든 메모리 주소 접근 - 2 bytes: short
- lowest 1 bit address must be 0 (2의 배수) - 4 bytes: int, float
- lowest 2 bits address must be 00 (4의 배수) - 8 bytes: double, long, char *(pointer)
- lowest 3 bits address must be 000 (8의 배수)
< Satisfying Alignment with Structures >
- 각 데이터 타입이 시작할 때는 그 타입의 배수에서 시작해야 한다.
- Structure의 끝에는 데이터 타입의 가장 큰 수의 배수로 끝나야 한다.


*17은 8의 배수가 아니므로 External Padding을 추가
< Arrays of Structures >
< Accessing Array Elements >
< Saving Space >
- External Padding is more efficient for memory space
< Memory Allocation of DIO_PORT_Odd_Interruptable_Type >
- Odd: Port 1
- Even: Port 2
< Memory Mapped I/O Address Example >
< Programming Exercise >
< Bit Operations >
Byte: CPU와 memory 간의 데이터를 읽고 쓸 때의 최소 단위
→ If you need to handle bit-wise operations, then you must use bit operators in C
< Unsigned Integers: Decimal, Binary, Octal, and Hexadecimal >
< AND, OR, XOR, NOT Operator >
*4개씩 묶으면 1111 0101 → F5
< %08x Modifier in Formatted I/O >
- %08x: hexadecimal 8자리로 출력 (주소가 32bit여서 8자리를 주로 사용)
- 빈 자리는 0으로 채워넣기
- a → %08x → 0000000a
a = 00001010
b = 00001100
a & b = 00001000 = 8
a | b = 00001110 = 14
a ^ b = 00000110 = 6
~ a = 11110101 = ~ 00001010 - 1= - 10 - 1 = - 11
< Left/Right Shift Operator (<< >>) >
- C언어에서 이진수의 맨 앞 자리 양수: 0, 음수: 1
- 빈 자리는 0으로 채워넣기
< %08x Modifier in Formatted I/O >
a = 00001010
a << 2 = 00101000 = 40
a >> 2 = 00000010 = 2
< Using Bit Operators: Setting a specific bit >
> Set a specific bit to '1'
- OR: (00101010) | (00000100) → 10101110
→ OR 1을 하면, 1이 된다.
- 1 << x: (00000001) → 1<<3 (1을 3번 shift left) → 00001000
→ 1의 위치를 이동시킨다.
> Set a specific bit to '0'
- AND: (10101010) & (11110111) → 10100111
→ AND 0을 하면, 0이 된다.
- ~(1 << x): (00000001) → 1<<3 (1을 3번 shift left) → 00001000 → ~ 00001000 → 11110111
→ 1의 위치를 이동시키고 ~을 하면, 해당 bit를 0으로 바꿀 수 있다.
< 예제 >
> Set a specific bit to '1':
DATA |= BIT6;
→ BIT6 = 0x0040 (16진수) = 0100 0000 (2진수)
→ DATA |= 01000000
→ DATA의 6번째 bit는 1이 된다.
DATA |= BIT7;
→ BIT7 = 0x0080 (16진수) = 1000 0000 (2진수)
→ DATA |= 01000000
→ DATA의 7번째 bit는 1이 된다.
> Set a specific bit to '0':
DATA &= ~BIT6;
→ BIT6 = 0x0040 (16진수) = 0100 0000 (2진수)
→ DATA &= ~(01000000)
→ DATA &= 10111111
→ DATA의 6번째 bit는 0이 된다.
DATA &= ~BIT7;
→ BIT7 = 0x0080 (16진수) = 1000 0000 (2진수)
→ DATA &= ~(10000000)
→ DATA &= 01111111
→ DATA의 7번째 bit는 0이 된다.
< Using Bit Operators: Checking a specific bit >
> Check if a specific bit is '1':
DATA & BIT6;
→ 값이 0이면 false (bit 값이 0이다), 값이 1이면 true (bit 값이 1이다)
예) 10101101 & 01000000 → 00000000
→ DATA의 6번째 bit 값은 0이다.
> Check if a specific bit is '0':
~(DATA & BIT6)
→ 값이 0이면 false (bit 값이 1이다), 값이 1이면 true (bit 값이 0이다)
예) ~(10101101 & 01000000) → ~(00000000) → 11111111
→ DATA의 6번째 bit 값은 0이다.
자료는 이화여자대학교 윤명국 교수님의 임베디드시스템및실험 강의에서 가져온 것입니다.
'Study > 임베디드시스템및실험' 카테고리의 다른 글
[Lecture 06] Polling & Pull-up register (1) | 2023.10.17 |
---|---|
[Exercise 04] 색깔 순서대로 LED 켜기 (1) | 2023.10.17 |
[Exercise 03] 두 LED 동시에 깜빡이기 (0) | 2023.10.17 |
[Lecture 04] LED (1) | 2023.10.16 |
[Exercise 02] Red LED 점차 빠르게 깜빡이기 (1) | 2023.10.15 |