• C++ 的部分移到 C++
    • 維護 C++ 中文版面。
  • 盡可能只紀錄語言層面知識。
    • Call by value: C 只有此種方法。
      • In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function (frequently by copying the value into a new memory region).
    • Call by reference: C++ 另外支援此種方法。C 可以用傳遞指針 (仍為 call by value,value 為位址) 模擬 call by reference 的效果。
      • In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value.

前處理器

常見問題

C

  • Ch1. C Through the Mists of Time
  • Ch2. It’s Not a Bug, It’s a Language Feature
  • Ch3. Unscrambling Declarations in C
    • typedef 閱讀方式和宣告一樣,為已有型別引入別名。
      // 看到 string,就是 char *。
      typedef char * string;
       
      // 常應用於簡化函式指針。
      void (*signal(int sig, void (*func)(int)))(int);
       
      // sig_t 是一個指針,指向一個參數為 int,返回值為 void 的函式。
      typedef void (*sig_t) (int);
       
      // signal 接受一個 int 和一個 sig_t, 返回 sig_t。
      sig_t signal(int sig, sig_t func);
      • 不建議。
  • Ch 4. The Shocking Truth: C Arrays and Pointers Are NOT the Same!
    • 定義 (definition) 確定對象 (object,鏈結器角度) 的型別並分配內存,創建對象。定義只能出現在一個地方。
    • 聲明 (declaration,或稱宣告) 描述對象的類型,引用定義在其它檔案的對象。聲明可以出現多次。

常見問題

    • 注意! strtok 會破壞被 tokenize 的字串,使用 strdup 拷貝一份備份供 strtok 使用。
    • strdup 參數若為 NULL,其行為未定義。
    • array 和 pointer 不等價。只有在某些情況下,array 操作會被轉換成 pointer 操作。
    • Porting to GCC 5
      // lib.h
      inline
      double dabs(double x) {
        return x < 0.0 ? -x : x;
      }
       
      // lib.c
      #include "lib.h" // 告知編譯器 dabs 的函式定義為何。
       
      // 指示編譯器在 lib.o 產生函式定義。
      extern inline double dabs(double x);
    • 為了讓編譯器能 inline 函式,inline 函式的定義一般都寫在 .h 檔。
    • C89 沒有定義 inline,inline 是 GCC 擴展 (GNU89),用於指示編譯器 inline function。
    • C99 以後對 inline 的解釋。
      • inline: 該函式定義僅用於 inline,不會產生函式定義。如果該函式被引用 (調用),則在其它檔案必須有該函式的定義。No externally visible function is generated. If the function is referenced in this TU, an external definition has to exist in another TU; same as GNU89 extern inline with no redefinition.
        // 此處的 add 定義只用於 inline function。
        inline int add(int i, int j) { return i + j; }
         
        int main() {
          // 如果編譯器無法 inline add 函式 (亦即透過函數調用 add),會產生 undefined symbol 錯誤。
          // 嘗試比較 -O0 和 -O2 的差別。
          int i = add(4, 5); 
          return i;
        }
      • extern inline: 最終會產生函式定義。
      • static inline: 不會產生函式定義。此函式只會在該定義所在的檔案被引用。

語言相關

#include <stdio.h>
 
int main()
{
  // 將整型 (int) -1,即 ffffffff,轉型成 size_t,進而得到 size_t 的最大值。
  // (~(size_t)0)
  size_t length = (size_t)-1;
 
  printf("max value of size_t: %zu\n", length);
  printf("sizeof(size_t): %lu\n", sizeof(size_t));
}
// $ cat /proc/`pidof mmap`/maps
// 00000000-100000000 rwxp 00000000 00:00 0
// 100000000-100001000 r-xp 00000000 00:0f 24080529                         /nfs_home/chenwj/tmp/mmap
 
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
 
// 4 * 1024 * 1024 * 1024 的寫法,會因為 4 預設型別為 int 而導致 overflow。
#define DEFAULT_CODE_GEN_BUFFER_SIZE (4UL << 30)
 
int main()
{
    void *ptr;
    size_t code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
    int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
 
    // gcc -Wl,-Ttext-segment=0x100000000 -fPIE -pie hello.c -o hello
    // mmap 映射虛擬位址 4G 以下所有空間。
     ptr = mmap(0, code_gen_buffer_size,
               PROT_WRITE | PROT_READ | PROT_EXEC,
               flags, -1, 0);
 
    if (ptr == MAP_FAILED)
    {
        printf("mmap failed!\n");
        abort();
    }
 
    printf("ptr: 0x%016lx\n", (unsigned long)ptr);
 
    sleep(100);
}

工作學習

轉換編碼

  • 如果看到轉碼之後,出現額外的亂碼。要確定拷貝的字串長度是正確的。strlen 是以 '\0'做為字串結尾,計算字串長度。因此,如果字串緩衝區中沒有 '\0',得到的長度不會是正確的。這可能是出現亂碼的原因。
    • 不確定欲處理的字串緩衝區是否有 '\0',避免使用 strlen 和 strcpy。改以 memcpy,並在額外配置的結尾處補上 '\0'。

其它

外部連結

登录