owned this note
owned this note
Published
Linked with GitHub
# [AIdrifter CS 浮生筆錄](https://hackmd.io/s/rypeUnYSb) <br> C 初次試煉
https://forum.xda-developers.com/showpost.php?p=78112850&postcount=6023
![](https://i.imgur.com/0Wv7Ihs.png)
# C
## Function Pointer Type
```C
typedef int(*OP)(int,int);
int add(int a , int b)
{
return a+b;
}
int main()
{
OP fun_ptr= add;
fun_ptr(3,1);
}
```
## Declare
```C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
int add(int num)
{
return ++num;
}
int sub(int num)
{
return --num;
}
int square(int num)
{
return num*num;
}
int main()
{
int Array1D[10];
int Array2D[3][10];
int *a[10] = {Array1D,Array1D+1,Array1D+2}; // 一個有10個指標的陣列,該指標是指向一個整數型的
int (*a1)[10] = Array2D; // 一個指向有10個整數型陣列的指標
int (*a2)(int) = add; // 一個指向函數的指標,該函數有一個整數型參數並返回一個整數
int (*a3[10])(int); // 一個有10個指標的陣列,該指標指向一個函數,該函數有一個整數型參數並返回一個整數
a3[0] = add;
a3[1] = sub;
a3[2] = square;
printf("(3+1) + (4-1) + (4*4) = %d \n",add(3) + sub(4) + square(4));
int non_const_num = 40;
int non_const_num1 = 50;
const int num = 10;
const int num1 = 20;
const int num2 = 30;
const int *foo = # // 一個 pointer,指向 const int 變數。
int const *foo1 = # // 一個 pointer,指向 const int 變數。
foo = &num1;
foo = &num2;
int* const foo2 = &non_const_num; // 一個 const pointer,指向 int 變數。
// foo2 = &non_const_num1; /* assignment of read-only variable ‘foo2’*/
int const *const foo3 = &num2; // 一個 const pointer,指向 const int 變數。
// foo3 = &num2; /* assignment of read-only variable ‘foo3’ */
return 0;
}
```
![](https://i.imgur.com/NnJDlxj.png)
## Const
const 通常表示**只可讀取不可寫入的變數**,常用來宣告常數。使用const有以下好處:
* 提升程式碼可讀性
* 使編譯器保護那些不希望被改變的參數
* 給優化器一些附加的資訊
編譯器處理方式 : define 在==預處理階段==展開;const 在==編譯階段==使用。
類型和安全檢查 : const 會在編譯階段會執行類型檢查,define 則不會。
存儲方式 : define 直接展開不會分配記憶體`gcc -E`,const 則會在記憶體中分配。
---
## inline
inline 可以將修飾的函式設為行內函式,即像巨集(#define)一樣==將該函式展開編譯,用來加速執行速度。==
## inline 和 #define 的差別在於:
* inline 函數只對參數進行一次計算,避免了部分巨集易產生的錯誤。
* inline 函數的參數類型被檢查,並進行必要的型態轉換。
* 巨集定義盡量不使用於複雜的函數
* **用 inline 後編譯器不一定會實作,僅為建議**。
---
## Volatile
* 被 `volatile` 修飾的變數代表它可能會被不預期的更新,因此告知
* 編譯器不對它涉及的地方做最佳化
* 每次操作它的時候都讀取該變數實體位址上最新的值,而不是讀取暫存器的值。
## 運用
* Interrupt service routines (中斷處理程式)
```C
int etx_rcvd = FALSE; // initialize etx
void main()
{
...
/* As far as the compiler is concerned,
* the expression !ext_rcvd is always true,
* and, therefore, you can never exit the while loop.
* Naturally, the blame will be placed on a "lousy optimizer."
*/
while (!ext_rcvd)
{
// Wait
}
...
}
interrupt void rx_isr(void)
{
...
if (ETX == rx_char)
{
etx_rcvd = TRUE;
}
...
}
```
* Multi-threaded applications (多線程應用程式)
* Despite the presence of queues, pipes, and other scheduler-aware communications mechanisms in real-time operating systems, it is still fairly common for two tasks to exchange information via a shared memory location (that is, a global). When you add a pre-emptive scheduler to your code, your compiler still has no idea what a context switch is or when one might occur. Thus, another task modifying a shared global is conceptually identical to the problem of interrupt service routines discussed previously. So all shared global variables should be declared volatile. For example:
* 在即時操作系統中(RTOS),除去佇列(queues)、管道(pipes)以及其他調度相關的通訊結構,在兩個任務之間採用共用的記憶體空間(shared memory location)(就是全局共用, global)實現資料的交換仍然是相當常見的方法。當你將一個優先權調度器應用于你的代碼時,編譯器仍然不知道某一程式段分支選擇的實際工作方式以及什麼時候某一分支情況會發生。這是因為,另外一個任務修改一個共用的總體變數在概念上通常和前面中斷處理程式中提到的情形是一樣的。所以,(這種情況下)所有共用的總體變數都要被聲明為volatile。例如:
```C
/*
* This code will likely fail once the compiler's optimizer is enabled.
* Declaring cntr to be volatile is
* the proper way to solve the problem.
* /
int cntr; // Sould set volatile
void task1(void)
{
cntr = 0;
while (cntr == 0)
{
sleep(1);
}
}
void task2(void)
{
cntr++;
sleep(10);
}
```
* 設備的硬體暫存器(如狀態暫存器)
* consider an 8-bit status register at address 0x1234. It is required that you poll the status register until it becomes non-zero. The nave and incorrect implementation is as follows:
* 假設我們有一個8位元的狀態暫存器映射在位址0x1234上。系統需要我們一直監測狀態暫存器的值,直到它的值不為0為止
* 錯誤的實現方法:
```C
uint * ptr = (uint *) 0x1234; // Wait for register to become non-zero.等待暫存器變為非0值
while (*ptr == 0);
// Do something else.作其他事情
```
```ASM
mov ptr, #0x1234
mov a, @ptr
loop bz loop
```
* 正確的實現方法:
```C
uint volatile *ptr = (uint volatile *) 0x1234;
```
```ASM
mov ptr, #0x1234
loop mov a, @ptr
bz loop
```
* const + volatile
* 這是在 RTOS kernel 常見的一種宣告:rt_clock通常是指系統時鐘,它經常被時鐘中斷進行更新。所以它是volatile。
* 而rt_clock通常只有一個寫者(時鐘中斷),其他地方對其的使用通常都是唯讀的。
```C
extern const volatile unsigned int rt_clock;
```
## Undefined Behavior
```C
// ++i;
add DWORD PTR [rbp-4], 1
mov eax, DWORD PTR [rbp-4]
// i++;
mov eax, DWORD PTR [rbp-4]
lea edx, [rax+1]
mov DWORD PTR [rbp-4], edx
```
```
int i = 10
i = i++ + ++i;
```
這個問題的標準答案是
```
i = i++ + ++i;
i = 10 + ++i;
i = 10 + 12;
i = 22
```
> 語言規格在定義時為了編譯器實做上的彈性和效率考量,會刻意不去規定某些規格,因此如果寫出來的程式依賴或著錯用某些沒有在規格內所規定的特性時,我們就稱之為Undefined behavior,
>
reference: [萬惡的未定義行為](http://blog.ez2learn.com/2008/09/27/evil-undefined-behavior/)
## Pointer to Pointer
![](https://i.imgur.com/KLWYgb6.png)
## Pointer Operation
- 指標位址不能相加,但是指標位址可以相減`offset`
- 指標相加: int *a + 5 = a + sizeof(int) * 5
- 指標相減: int *a - int *b = a 和b 中間差幾個element
```C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
int main()
{
int *a, *b;
a = (int *)1;
b = (int *)1;
printf("%d %d %d\n", a + (int)b, (int)(a + (int)b), (int)a + (int)b);
// 5 5 2
a = (int *)0x5566;
b = (int *)0x5570;
printf("%d %d %d %d %d\n", a, b, (int)a+(int)b, a+(int)b, sizeof(int *));
// 21862,21872, 43734 , 109350 , 8
printf("%d\n", a - b);
// -10/4 = -2.5 Complement is -3
printf("%d\n", ((int)b - (int)a)/sizeof(int *));
// 10/8 = 1
a = (int*)0x1000;
b = a + 3;
printf("%d %d %p %p \n", a, b, a, b);
// 4096, 4108 0x1000, 0x100c
system("pause");
return 0;
}
```
## const int* p 和 int* const q 兩者之差別:
* 前指標指的內容不可變動,後指標不可變動
* C++
* void dp()const; // 我不會更改成員 const member function
* const int* op() const{return &data;} // 回傳const參考 保證不會更改
---
## Interrupt Service Routine 之錯誤
```C
__interrupt double isr(double r) //不能有參數
{
double area = PI*r*r ;
printf("%f\n",area) ; //改成printk
return area ; // 不能有return
}
```
- ISR不能有返回值(不知道給誰)
- ISR不能傳遞參數(不知道誰呼叫)
- `pintf()`改`printk()``
- ISR應短而高效
## 一行程式碼 N是否為判斷2的次方
```C
boolean isPowerof2(int n) {
//return n > 0 && (n & (n - 1)) == 0;
return ((n&-n)==n)?true:false
}
```
二進位中,只要是 2 的次方,都剛好會是像 100 (4)或者 1000 (8)這種 1 開頭,尾巴都是 0 的狀況
```
8 的二進位 1000
7 的二進位 0111
1000
&
0111
-----
0000 = 0 (return true)
```
Reference: http://davidhsu666.com/410/ispowerby2
## Fun Array
```C
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *p = &(a + 1)[3];
printf("%d\n", *p);
```
輸出 5
因為a+1指向a的第二個元素,[3]表示再向後移動3個元素
`a+1`是跳一個int的大小(a想成指標)
`&a+1`是跳一整個array的大小
## What's wrong on the code.
- Wrong version
```C
void GetMemory(char *p) {
p=(char *)malloc(100);
}
void test() {
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
```
- Correct version
```
int GetMemory(char **p, int num) {
*p=(char *)malloc(num);
if(*p==NULL)
{
return -1; // memory allocated failed
}
return 0;
}
void test() {
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello world");
puts(str);
}
```
- Wrong version
```C
swap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
```
- dereference *p 會core dump
- swap 需要return value;
```C
// stupid way
swap( int* p1,int* p2 )
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
// bit wise
swap( int* p1,int* p2 )
{
*p1 = *p1^*p2;
*p2 = *p1^*p2;
*p1 = *p1^*p2;
}
```
## C Operator Precedence
![](https://i.imgur.com/Yl7Q30M.png)
- `++` > `*`
- 元素位移
```C
int main()
{
char s[] = "0113256";
char *p = s;
printf("%c", *p++); // s[1] 1
printf("%c", *(p++)); // s[2] 1
printf("%c", (*p)++); // s[2] 2
printf("%c", *++p); // s[3] 3
printf("%c", *(++p)); // s[4] 2
printf("%c", ++*p); // s[4] 3
printf("%c", ++(*p)); // s[4] 4
puts(p); // 0123456
return 0;
}
```
## Bitwise
### Arithmetic Right Shift
- **無號數補0 有號數補1**
```C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
uint32_t count_bit(uint32_t x)
{
uint32_t i = 0, count = 0;
for (; i<sizeof(x)*8; i++)
if((x>>i)&1)
{
printf("1");
count++;
}
else
printf("0");
puts("");
return count;
}
uint32_t reverse_uint32_t(uint32_t x)
{
}
int main()
{
int signed_X = 0xffffffff;
unsigned int X = 0xffffffff;
printf(" x = %u\n", X);
count_bit(X);
count_bit(X>>3);
count_bit(X<<3);
printf(" signed = %d \n", X);
count_bit(signed_X);
count_bit(signed_X>>3);
count_bit(signed_X<<3);
return 0;
}
```
```shell
aidrifter@aidrifter-VM$ ./a.out
x = 4294967295
11111111111111111111111111111111
11111111111111111111111111111000
00011111111111111111111111111111
signed = -1
11111111111111111111111111111111
11111111111111111111111111111111
00011111111111111111111111111111
```
### x 的補數-x 與 ~x
- `-x = ~x + 1`
```shell
001000 // 8
111000 // -8 = -32 + 16 + 8
001001 // 9
110110 // -9 : -x = ~x + 1
110111 // (-2^5) + ((2^5 - 1) - 2^3)
111111 // -1
111011 // -1 + 4
100101 // -32 + 4 + 1
```
### Integer++ --
- `-x = ~x + 1` = `-x = ~x - (-1)`
```C
// 注意:比直接加一和減一還要慢。
int add_one(int x)
{
return -~x; // ++x
// x: 1001001
// ~x: 0110110
// -~x: 1001010
}
int sub_one(int x)
{
return ~-x; // --x
// x: 1001001
// -x: 0110111
// ~-x: 1001000
}
```
### unsinged to signed
```C
int negative(int x)
{
return ~x + 1; // -x;
}
int negative(int x)
{
return (x ^ -1) + 1; // -x;
}
```
### even or odd
```C
bool is_odd(int x)
{
return x & 1; // x % 2;
}
```
### Absolute value
```C
int absolute(int x)
{
return ((x>0)?x:-x);
}
int abs(int x)
{
// x < 0 ? -x : x;
// x >> 31 = 111...111 (如果x是負數) or 000...000 (如果x是正數)
// x ^ (x>>31) => 如果 x 為負數則將 x 的 0轉1, 1轉0, 如果 x 為正數, 則保持x 不變.
// (x ^ (x >> 31)) - (x >> 31) => 如果 x 為正數則 x-0=x , 如果 x 為負數則 ~x-(-1) = -x
return (x ^ (x >> 31)) - (x >> 31);
}
```
### 最低位的位元
```X
int lowest_bit_1(int x)
{
return x & -x;
}
```
### is 2 exponation ?
```C
bool is_power_of_2(int x)
{
return (x & -x) == x;
}
```
### is it square ?
- 1+3+5+7+....+(2*n-1)=n^2
```C
bool square(int x)
{
int i , sum =0 ;
for (i=1;i<=2*n-1;i+=2)
sum += i;
return (sum==x*x)?true:false;
}
```
### swap
```C
void swap(int *a, int *b)
{
*a = *a^*b
*a = *a^*b
*a = *a^*b
}
```
### How to compute number of 1
```C
uint32_t count_bit(uint32_t x)
{
uint32_t i = 0, count = 0;
for (; i<sizeof(x)*8; i++) // or n!=0
if((x>>i)&1)
count++;
return count;
}
int count_bits2(unsigned int n) {
int i=0;
for ( ; n != 0; n >>= 1)
if (n & 1)
++i;
return i;
}
```
### reverse integer
```C
uint32_t reverse_uint32_t(uint32_t x)
{
int i;
int ret = 0;
for (i=0; i < sizeof(x)*8; i++)
ret |= ((x&(1<<i))>>i)<<(sizeof(x)*8-i-1);
// better way
// ret |= (x>>i&1)<<(sizeof(x)*8-i-1);
return ret;
}
```
Reference:
C bitwise operation
http://puremonkey2010.blogspot.com/2011/05/c-bitwise-operation.html
### Dangling pointer
```C
{
char *cp = NULL;
/* ... */
{
char c;
cp = &c;
} /* c falls out of scope */
/* cp is now a dangling pointer */
}
```
# OS
## processes vs threads
## process
Reference:
linux C 語言編程
https://www.byvoid.com/zht/blog/linux-c-1
Linux Processes – Process IDs, fork, execv, wait, waitpid C Functions
https://www.thegeekstuff.com/2012/03/c-process-control-functions/
AIdrifter CS浮生筆錄: Multi thread
https://hackmd.io/McOLfJwIRXWnJLKmiEgfww
## thread
You need to add ` gcc pthread.c -lpthread` when compiler time to solve `undefined reference to "pthread_create"`
```C
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <signal.h>
#define gettid() syscall(SYS_gettid)
void *print_message_function( void *ptr );
int main()
{
pthread_t thread1, thread2;
const char *message1 = "Thread 1";
const char *message2 = "Thread 2";
int iret1, iret2;
/* Create independent threads each of which will execute function */
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
if(iret1)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",iret1);
exit(EXIT_FAILURE);
}
iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);
if(iret2)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",iret2);
exit(EXIT_FAILURE);
}
printf("pthread_create() for thread 1 returns: %d\n",iret1);
printf("pthread_create() for thread 2 returns: %d\n",iret2);
/* Wait till threads are complete before main continues. Unless we */
/* wait we run the risk of executing an exit which will terminate */
/* the process and all threads before the threads have completed. */
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(EXIT_SUCCESS);
}
void *print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf("%s tid : %u pid : %u\n", message, gettid(), getpid());
sleep(10);
}
```
```shell
aidrifter@ubuntu$ ./a.out
pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
Thread 1 tid : 51509 pid : 51508
Thread 2 tid : 51510 pid : 51508
```
### Deadlock
每一種資源都有一定的instances,像是可能有五個disk,不止一個的I/O devices,每一個
process 要利用資源都有以下三種階段
要求資源
使用資源
釋放資源
DeadLock Character
- Mutual exclusion(互斥)
- Hold & wait(持有並等待) (Partial Allocation)
- No preemption(不可強取豪奪)
- Circular waiting(循環等待)
### mutex
- pthread
-
### fork
fork()
Purpose is to create a new process, which becomes the child process of the caller
Both processes will execute the next instruction following the fork() system call
Two identical copies of the computer's address space,code, and stack are created one for parent and child.
### Memory layout
```C
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
char globBuf[65536]; /* Uninitialized data segment */
int primes[] = { 2, 3, 5, 7 }; /* Initialized data segment */
static int
square(int x) /* Allocated in frame for square() */
{
int result; /* Allocated in frame for square() */
result = x * x;
return result; /* Return value passed via register */
}
static void
doCalc(int val) /* Allocated in frame for doCalc() */
{
printf("The square of %d is %d\n", val, square(val));
if (val < 1000) {
int t; /* Allocated in frame for doCalc() */
t = val * val * val;
printf("The cube of %d is %d\n", val, t);
}
}
int
main(int argc, char *argv[]) /* Allocated in frame for main() */
{
static int key = 9973; /* Initialized data segment */
static char mbuf[10240000]; /* Uninitialized data segment */
char *p; /* Allocated in frame for main() */
p = malloc(1024); /* Points to memory in heap segment */
doCalc(key);
exit(EXIT_SUCCESS);
}
```