2020年4月19日 星期日

Computer Science - MSB LSB

MSB = Most Significant Bit


    簡單來說等於最左邊的 Bit第 2^{n-1} 的 Bit

LSB = Least Significant Bit


    簡單來說等於最右邊的 Bit,第 0 位的 Bit

MS Byte、LS Byte


    Bit 換成 Byte 的概念。

C 語言 - function pointer 函數指標

function pointer 概念


    基本上有 data 的 pointer 就會有 function 的 pointer。
  • 正確的 ( 回傳 int 的 function )
  •     int (*pfi)();
  • 錯誤的 ( 回傳 int pointer 的 function )
  •     int *pfi();

function pointer 宣告


    利用 typedef,然後一樣用 & 取 function pointer
    extern int f1();
    
    typedef int (*funcptr)();
    funcptr pfi;
    pfi = &f1;
    實際上你可以省略 &,因為 function 若不呼叫,他就只能回傳 pointer ( 原文 : When you mention the name of a function but are not calling it, there's nothing else you could possibly be trying to do except generate a pointer to it. )
    pfi = f1;

function pointer 呼叫

  • 正確的 ( 回傳 int 的 function )
  •     int (*pfi)(arg1, arg2);
  • 錯誤的 ( 回傳 int pointer 的 function )
  •     int *pfi(arg1, arg2);
  • 省略的 ( 原理同上,function pointer 除了 Call function 只能 assign 另一 pointer 或比較其值,所以 Compiler 會將 pfi 視為 (*pfi)。) ( 原文 : There's nothing you can do with a function pointer except assign it to another function pointer, compare it to another function pointer, or call the function that it points to. )
  •     int pfi(arg1, arg2);

下一篇 : 

C 語言 - size_t 及各個常見類型

    typedef unsigned int size_t // 通常定義在 stddef.h

    int8     : -128 ~ 127
    int16    : -32768 ~ 32767
    int32    : -2147483648 ~ 2147483647
    int64    : -9223372036854775808 ~ 9223372036854775807
    
    uint8    : 0 ~ 255
    uint16   : 0 ~ 65535
    uint32   : 0 ~ 4294967295
    uint64   : 0 ~ 18446744073709551615

    uint8_t  : 0xFF
    uint16_t : 0xFFFF
    uint32_t : 0xFFFFFFFF
    uint64_t : 0xFFFFFFFFFFFFFFFF

C 語言 - malloc、free 與 calloc

malloc 跟 free


    一般來說要將函式結果回傳是不能用 pointer,因為一旦函式結束 stack 的空間就會被釋出,所以 pointer 會指向的資料是危險的。這時就會先動態地宣告一個位址給 pointer,但這類的記憶體會被存放在 heap 而非 stack,所以開發者必須自行釋放。
  • pointer.c
  •     void
        showMalloc(int pointerValue)
        {
            int *p = malloc(sizeof(int));
    
            printf("Address : %p\n", p);
            printf("Value   : %d\n", *p);
    
            *p = pointerValue;
    
            printf("Address : %p\n", p);
            printf("Value   : %d\n", *p);
            
            free(p);
        }
  • output
  •     Address : 00682B90
        Value   : 6826496
        Address : 00682B90
        Value   : 100

calloc


    會幫你初始值的 malloc
  • pointer.c
  •     void
        showMalloc(int pointerValue)
        {
            int *p = calloc(1, sizeof(int));
    
            printf("Address : %p\n", p);
            printf("Value   : %d\n", *p);
    
            *p = pointerValue;
    
            printf("Address : %p\n", p);
            printf("Value   : %d\n", *p);
    
            free(p);
        }
  • output
  •     Address : 00722B90
        Value   : 0
        Address : 00722B90
        Value   : 100

參考資料 :
https://openhome.cc/Gossip/CGossip/MallocFree.html

C 語言 - #ifndef

#ifndef 用途

  • 在 .h 檔確保只會被編譯一次
  •     #ifndef HELLO_H // 有些人會定義成 _HELLO_H_
        #define HELLO_H // 但目的就是不會被重複編譯
    
        #include <stdlib.h>
    
        int helloIntro(char** str);
        int main() __attribute__((weak));
    
        #endif

C 語言 - 編譯多個含有 main function 的 C code

編譯多個含有 main function 的 C code


    理論上是不行,GCC 無法自行繞過某某函式去編譯,通常是給條件去讓編譯器來達到 "只有一個你想要的 main function" 編譯目的。有人會問為什麼會有多個 main function,我想多半是因為想 Debug。

1. 利用 #ifdef

  • other.c
  •     #ifdef DEBUG
        int main ()
        {
            return 0;
        }
        #endif
  • gcc
  •     gcc -DEBUG other.c -o other.x

2. 利用 __attribute__((weak))

  • other.h ( __attribute__((weak)) 只能在宣告 function 時作 )
  •     int main() __attribute__((weak));
  • other.c
  •     int main ()
        {
            return 0;
        }

參考資料 :
https://stackoverflow.com/questions/35510670/compile-c-code-without-its-main-function

2020年4月14日 星期二

C 語言 - sprintf / snprintf

sprintf (char *s, const char *format, ...)

    C 語言並沒有其他語言方便的 container 去作字串轉換,所以 sprintf 就顯得強大許多。原理就是 printf 但輸入到字串。但會有 overflow 的 issue 產生。
    int main()
    {
        char str[5];
        sprintf(str, "ABC");
        printf("%s\n", str); // output : ABC
        return 0;
    }
    int main()
    {
        char str[5];
        sprintf(str, "ABCDEF");
        printf("%s\n", str); // output : ABCDEF
        return 0;
    }

snprintf (char *s, size_t maxlen, const char *format, ...)

    snprintf 多了一個參數去限制寫入長度(包含'\0'),安全許多。另外我是用 gcc 編譯的,snprintf 會回傳寫入字串的長度 (不包含'\0'),所以當回傳值大於等於 maxlen,則代表字串被切了。
    int main()
    {
        int ret;
        char str[5];
        ret = snprintf(str, 5, "ABC");
        printf("%s\n", str); // output : ABC
        printf("%d\n", ret); // output : 3
        return 0;
    }/code>
    int main()
    {
        int ret;
        char str[5];
        ret = snprintf(str, 5, "ABCDEF");
        printf("%s\n", str); // output : ABCD
        printf("%d\n", ret); // output : 6
        return 0;
    }


參考資料:
https://blog.xuite.net/tzeng015/twblog/113272245-snprintf
https://linux.die.net/man/3/snprintf

2020年4月13日 星期一

C 語言 - Linux System Log

Linux - System Log

    Linux 當事件發生會產生 log,通常會存在 /var/log 底下。優先度如下。
  •     debug
  •     info
  •     notice
  •     warning
  •     err
  •     crit
  •     alert
  •     emerg/panic

C 實作 - void syslog(int priority, const char *format, ...)

    #include<stdio.h>
    #include<stdlib.h>
    #include<syslog.h> 
    syslog(LOG_INFO, "hello %s", "woring");
    syslog(LOG_ERR,  "hello %s", "test");
底下為參數 int priority
LOG_USER : A miscellaneous user process
LOG_MAIL : Mail
LOG_DAEMON : A miscellaneous system daemon
LOG_AUTH : Security (authorization)
LOG_SYSLOG : Syslog
LOG_LPR : Central printer
LOG_NEWS : Network news (e.g. Usenet)
LOG_UUCP : UUCP
LOG_CRON : Cron and At
LOG_AUTHPRIV : Private security (authorization)
LOG_FTP : Ftp server
LOG_LOCAL(0~7) : Locally defined

參考資料 :
https://ithelp.ithome.com.tw/articles/10159084
http://yu-minspace.blogspot.com/2007/09/linux-syslogd-openlogsyslogdsyslog.html

2020年4月12日 星期日

C 語言 - __attribute__((weak))

使用的情境

    假設我們不知道外部是否會提供 foo() 這個 function,若沒有則用自己的 foo()。
    extern int func(void);
    int __attribute__((weak)) func(void)
    {
        return 0;
    }

備註 - 不會在動態函式庫 (.so) 中生效

    string.so
    void real_func()
    {
        printf("strong func\n");
    }
    weak.so
    void real_func() __attribute__((weak))
    {
        printf("weak func\n");
    }
    main.c
    extern void real_func();
    void main()
    {
        real_func();
    }
結果 :
    // 動態連結無效,只看順序
    gcc main.c -lstrong -lweak // 輸出 : strong func
    gcc main.c -lweak -lstrong // 輸出 : weak func

    // 正常 .o 檔
    gcc main.c weak.o strong.o // 輸出 : strong func
    gcc main.c strong.o weak.o // 輸出 : strong func


參考資料 :
https://www.itread01.com/content/1541531526.html

C 語言 - unsigned char

char 與 unsigned char 的區別

    單看兩個變數類型是沒有差別的, char -128 ~ 127, unsigned char 0 ~ 255,範圍大小一樣,並沒差別。唯一差別是在賦值的時候

賦值的時候 char 與 unsigned char 的區別

    (signed) char 有符號 bit ,這會導致你在賦予值時,(signed) char 會依照情況去賦予值。
    void unsignedcharTest(unsigned char value)
    {
        char c = value;
        unsigned char uc = value;
        int char_to_int = c;
        int unchar_to_int = uc;
        unsigned int char_to_unint = c;
        unsigned int unchar_to_unint = uc;
        printf("%%c: %c, %c\n", c, uc);
        printf("%%X: %X, %X\n", c, uc);
        printf("%%d: %d, %d\n", char_to_int, unchar_to_int);
        printf("%%u: %u, %u\n", char_to_unint, unchar_to_unint);
    }

    int main()
    {
        unsignedcharTest(0x7F); // 0111 1111 符號 bit 為 0 不會擴展
        unsignedcharTest(0x80); // 1000 0000 符號 bit 為 1 會擴展,補 1  
        return 0;
    }
    結果 :
    %c: , 
    %X: 7F, 7F
    %d: 127, 127
    %u: 127, 127
    %c: , 
    %X: FFFFFF80, 80
    %d: -128, 128
    %u: 4294967168, 128

參考資料 :
https://www.itread01.com/content/1547130625.html

C 語言 - static

static - Introduction

     靜態變數(Static Variable)在電腦編程領域指在程式執行前系統就為之靜態分配(也即在執行時中不再改變分配情況)儲存空間的一類變數。與之相對應的是在執行時只暫時存在的自動變數(即局部變數)與以動態分配方式取得儲存空間的一些物件,其中自動變數的儲存空間在呼叫棧上分配與釋放。

static + 變數

  
    (1) 宣告在 function 內 ( 記憶體模式 )
    這是比較經典的 Case,因為 Static 參數不會隨著 function 結束而消逝,所以可以用來計算 function 被呼叫的次數。
    #include "hello.h"

    int count(){
        static int count = 0;
        ++count;
        return count;
    }
    (2) 宣告在 function 外 ( 連結模式 ) 
    假設 a.h 跟 b.h 都設了 void foo() 這個函式,這樣你在 main.c 同時 include 時就會編譯錯誤。你有可能會說那我把 void foo() 個別放在 a.c 跟 b.c 就行,但編譯依然會錯誤。因為在連結 .o 檔時編譯器依然會發現。這時 static 就可避免此情況,有點類似 private 的概念,只有自己看得到就不會產生 ambiguous 的問題。


參考資料 :
https://zh.wikipedia.org/wiki/
https://medium.com/@alan81920/

Popular Posts