bloggerads

顯示具有 C & CPP 標籤的文章。 顯示所有文章
顯示具有 C & CPP 標籤的文章。 顯示所有文章

2021年6月26日 星期六

C/C++ in Arm Cross Compiler

in Arm, C++ compiler recognizes keyword: extern "C", and the Macro __cplusplus

In C header files, add __cplusplus to make sure the header files can be recognized by C++, as following

#ifdef  __cplusplus // This statement is true in C++ but false in C
extern "C"
{
#endif

//Original Header File Contents

#ifdef __cplusplus
}
#endif

In C++, 

If you'd like to include a C header file without changing the C header, you can do like:

extern "C"{
     #include "CHeader.h"
}

If you'd like to export a function to C, you can do like:

extern "C" int OutputApi(int);



<NOTE>
A header file can only be compiled one time.
So it is needed to add a pure C type header file additionally to designate what C++ exported functions.
This C type header file is actually included in other C source files. (not in C++)
Following are the workable method to achieve the C/C++ cross compiler in ARM.

a.cpp
void aa(void){}

a.h
#ifdef  __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
EXTERN_C  void aa(void);

intermediate.h
include <a.h>

b.c
include <intermediate.h>
void call_c()
{
    aa();
}

2017年4月19日 星期三

C : 好用的parsing 數字字串函式 strtol

strol (Convert string to long integer)

須include stdlib.h, 他的原型是 

long int strtol (const char* str, char** endptr, int base);

return value 是 轉換後的十進位值

第一個引數 str 是待轉換的數字字串指標

第二個引數 endptr 則是提供回傳parsing整串字串中, 空白字元分隔的下一個數字字串位址。 如果不用回傳,則給 NULL 即可

第三個引數是說明以什麼格式來 parsing 這個數字字串,  如 2 進位就給 2, 16 進位就給 16, 0 就是 自動偵測數字字串的格式。 (ps.) 16 進位可接受開頭為0x, 亦可接受大小寫

2017年4月8日 星期六

利用C語言的正規表達功能來Parsing 傳入程式中的引數

這篇介紹 C 的 sscanf 函數來做到類似 C++11 正規表達的效果,並以 Parsing 傳入程式中的引數做範例
// c.cpp

int main(int argc, char* argv[])
{
    char s0[30], s1[30];
    int ret;
    for (int i=argc-1; i>0; i--) {
        s0[0] = s1[0] = 0;
        //sscanf(argv[i], "%*[^:]:%s", s0); //[^:]代表在':'處設斷點但不包含':', '*'代表忽略'%'起始的字串
        sscanf(argv[i], "-%29[^:]:%29s", s0, s1); 
        if (s0[0] == 0 || s1[0] == 0) 
            puts("Wrong type!");
        else            
            printf("%s : %s\n", s0, s1);
    }   
  return 0;
}

----------------------Output---------------------------
> g++ -o c c.cpp
> c -name:John -age:20
age : 20
name : John

2017年2月5日 星期日

DOS : Legacy Graphic Output Control

在Dos下想輸出文字到螢幕上,除了呼叫C/C++提供的函數 printf, cout 或 Bios提供的軟體中斷 int 10, 是否有直接控制硬體的方法呢?  答案是有的,可以直接把要顯示的資料搬到A/B Segment。用以下的code來做範例 (Compile using Watcom)

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;

 enum Colour{ BLACK=0, BLUE, GREEN, CYAN, RED, MAGNETA, BROWN, LGRAY, \
   DGRAY=8, LBLUE, LGREEN, LCYAN, LRED, LMAGNETA, YELLOW, WHITE};
 
#define COLOUR(forecolour, backcolour)  ((backcolour) << 4 | (forecolour) & 0x0F)

 void WriteString(int y, int x, BYTE colour, char *string)
 {
     volatile WORD *pvram;
     
     for (DWORD i=0;string[i]!=0; x++, i++) {
       pvram = (volatile WORD *)0xB8000 + y * 80 + x;
       *pvram = (BYTE)string[i] | colour << 8;
     }
 }
 

 void WriteCharacter(int y, int x, BYTE colour, BYTE ch)
 {
      volatile WORD * pvram;
      pvram = (volatile WORD *)0xB8000 + (y * 80 + x) ;
      *pvram = ch | (colour << 8);
 }

 int main()
{
     WriteCharacter(1,0, COLOUR(RED, BLACK), 'H');    
     WriteCharacter(1,1, COLOUR(RED, BLACK), 'i');
     WriteString(1, 3, COLOUR(GREEN, BLACK), "Martin.");
}

在螢幕座標(y,x) = (1, 0) 秀出 Hi Martin.


ps. 如果想畫一個點陣圖請參考 mode 13h, 解析度為320*200, 256色, 透過寫入A000:0來完成


題外話, 我用了以上的技巧寫了一個Dos版的source code Editor, 名稱叫E editor (下圖)。 平常工作時都會開個Dos模擬器跑Dos tool,享受Dos單純的美。



Key:
F1: Copy Line
F2: Paste Line
F3: Delete Line
F10: Save File

下載: (password: martinlee)

E Editor

2016年12月2日 星期五

gcc : Built-in functions for atomic memory access

這一篇是研究Memory barrier的心得。研究的原因是因為在UEFI環境下使用multi-processor protocol 來驗證CPU design,過程用到了相關的gcc Atomic函式。Atomic 提供同步機制,使得在Multi-Processor/Multi-Thread的系統下操作同一塊memory, 各個Core的Cache都能確保和Memory同步。

這邊只是以軟體thread寫個應用程式作範例來解釋Memory barrier, 如果不使用Built-in functions for atomic memory access而將__sync_fetch_and_add(&count,1);改成count++, 則count結果會不正確。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

static int count = 0;

void *MyTest(void *arg)
{
        for (int i=0; i<20000; ++i)         
            __sync_fetch_and_add(&count, 1);
        return NULL;
}

int main(int argc, const char *argv[])
{
        pthread_t Thread_Id[10];
        int i;

        for (i=0;i<10;++i)
                pthread_create(&Thread_Id[i], NULL, MyTest, NULL);
       
                // Wait until all threads have finished.
        for (i=0;i<10;++i)
                pthread_join(Thread_Id[i], NULL);
       
        printf("%d\n",count);
        return 0;
}


另外,__sync_synchronize (): This built-in function issues a full memory barrier.呼叫這個函式讓每個Core上的cache和memory同步。

<note> UEFI kernel提供EFI_MP_SERVICES_PROTOCOL,透過這個protocol,可以指定呼叫某個/或多個CORE (AP)分別執行特定的function,達到Multi-processing的效果。

-------------------------------------------------------------------------------------------------------------------------
Ps. windows下測試,需要自行加入pthread這個library
如果你用Dev-C++ 5.11, Project->Parameters->Add library or object 加入
"../../Program Files/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib/libpthread.a"



順便解釋一下我認知的procces/thread:

process: 在系統中被註冊要執行的程式,其擁有CPU的使用權和獨立的位址空間。
thread: 系統處理工作的基本單位,一個CPU核心在同一時間只能提供一個thread來執行process
Multi-Thread: 將多個thread同時assign給一個process
Multi-Process: 每個process都分到thread來處理

2016年11月15日 星期二

g++ : libgcc_s_dw2-1.dll is missing

解決某些Windows平台在執行exe檔時,找不到libgcc_s_dw2-1.dll。缺少的這個dll應該是C++的library
我的g++版本(gcc -v): 4.8.1

解決方法就是在compile code 時加入 -static-libgcc  -static-libstdc++ 參數把所需要的library包進去

如下:
g++ -o main main.cpp 改成 
g++ -o main -static-libgcc  -static-libstdc++ main.cpp

2016年6月3日 星期五

LeetCode : 169. Majority Element

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.


// C++ Solution

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        if (nums.size() == 1) return nums[0];
        map <int, int> m;
        for (int i=0; i<nums.size(); i++) {
            if (m.find(nums[i]) == m.end() )
                m[nums[i]] = 1;
            else {
                m[nums[i]]++;
                if (m[nums[i]] > nums.size()/2)
                    return nums[i];
            }
        }
    }
};

2016年1月14日 星期四

Hook my own interrupt vector in DOS

因為工作上需要驗證中斷的tool, 所以把塵封已久的Watcom DOS程式拿出來改。以下是一個基本的掛中斷、呼叫中斷、移除中斷的範例
// Author: Martin Lee  

 #include <stdio.h>
 #include <conio.h>
 #include <dos.h>

 #define getvect(n) _dos_getvect(n)

 #define setvect(n,v) {\
   _disable();\
   _dos_setvect(n,v);\
   _enable();\
 }

 #define HOOKVECTOR 0x7F

 int sig;

 void interrupt  (*origin_int)();

 void interrupt handle_7Fh(void)
 {
     sig=1;
     //_chain_intr( origin_int); // not execute original vector
 }

 void hook_int(void)
 {
     origin_int = getvect(HOOKVECTOR);
     setvect (HOOKVECTOR, handle_7Fh);
 }

 void restore_int(void)
 {
     setvect(HOOKVECTOR,origin_int);
 }

 void main()
 {
     sig = 0;

     hook_int();

     printf("Before int 7fh, sig = %d\n", sig);

     __asm  int 7Fh    
   
     printf("After int 7fh, sig = %d\n", sig);
       
     restore_int();
   
 }

----------------------執行結果-----------------------------
Before int 7fh, sig = 0
After int 7fh, sig = 1


2014年12月10日 星期三

C++ Compiler : g++ 指令介紹

以下提供一些g++指令參數解釋,基本上就是用來生成執行檔/dll檔/obj檔

# Generate file.o

g++ -c file.cpp  

# Generate Assembly : file.s 

g++ -S file.cpp  

# Convert file.o to file_dll.dll (需要先把cpp檔做成obj檔再來轉成dll檔)

g++ -shared file.o -o file_dll.dll 

# Generate file.exe

g++ file.cpp  -o file 

# Generate file.exe from object and cpp files

g++ file.cpp  obj.o -o file 

# Generate main.exe from dll and cpp files

g++ file_dll.dll main.cpp -o main

# Alternative solution to generate main.exe from file_dll.dll  and main.cpp ,  -L. means current dir

g++ -L. -lfile_dll main.cpp -o main 

# Show all the warning
gcc -Wall -o main main.c

# Warning as error
gcc -Wall -Werror -o main main.c

2014年10月25日 星期六

C/C++一些經驗談

一些雜談,提供個人Coding 的經驗

1. 無窮迴圈的例子: 沒有注意宣告的變數範圍上限或邏輯錯誤而溢位產生無窮迴圈
  1. for (unsigned char x=0; x<=0xff; x++) ;
  2. for (unsigned char x=0xff; x>=0; x--) ;
2. 宣告雙指標的時機
用指標來管理記憶體,而雙指標(指標的指標)就是用指標管理指標
實務上在函式間傳遞指標的位址時, 就必需要傳遞指標的指標。舉個記憶體管理的例子,假如我有一串link list如下p1~p6,就可以透過雙指標pp start/pp tail指定鏈結串鏈其中一段的起始節點位址(&p2)和尾部節點位址的(&p5), 而PP start/ PP tail就是雙指標的型態

2014年9月26日 星期五

C 結構(structure) 的一些注意事項 (C89 / C99 / 對齊,Alignment)

1. 結構變數初值給定

首先,先宣告一個結構型態, 接下來再介紹兩種初值給定方法(C99/C89):
+  struct test
+  {
+    const char* cap;
+    unsigned char data_0;
+    int data_1;  
+  };

support C99 mode (現在新版本的GCC都有support C99 mode 的結構變數初值給定方法。 這種方法的優點是未來如果結構調整變數的位置,宣告變數初值不用跟著調整):

+  struct test node = 
+  {
+      .cap="first", 
+      .data_0=10,
+      .data_1=5
+  };

以下是傳統(C89 mode)的寫法 (很可惜的是目前Watcom C版本(1.9)尚未支援C99 mode結構變數的初值給定方法),所以還是用舊有的寫法:

+  struct test node = 
+ {
+      "first",   // cap
+      10,       // data_0
+      5          // data_1
+  };

2. 結構內變數對齊(alignment)的問題

2014年7月25日 星期五

在DOS下寫程式常會用到的中斷 (to DOS愛好者)

現在還在用Dos的人其實不少只是比較不顯眼 :P ,就我知道幾乎所有的x86系統在開發過程中,還是以Dos tool來驗證chipset問題。(畢竟誰會這麼閒重新在UEFI shell上開發以前在Dos下沒問題的程式XD)

我也是Dos的愛用者,開發過的Dos測試程式比在其他作業系統上的測試程式多得多,寫程式的功力也是從這邊開始練起。

基本上使用Watcom若是default使用protect mode, 那麼寫Dos程式幾乎跟在windows上感覺差不多,但是Watcom可以透過inline assembly神不知鬼不覺地使用原始 real mode 的中斷。

由於中斷很多,這篇僅列出我常使用的中斷給大家參考:

1. Access PCI configuration: INT 1A

提供範例函數來讀取PCI cfg data:
+
+  //Author: Martin Lee
+   const unsigned char PCI_FUNCTION_ID= 0xB1;
+   const unsigned char READ_CONFIG_DWORD 0x0A
+   
+   DWORD READ_PCI_CONFIG_DWORD(WORD BDF, WORD index)
+   {
+   
+      DWORD data;
+       __asm
+       {
+       // 1AB109 INT 1A - PCI BIOS v2.0c+ - READ CONFIGURATION WORD
+       // BH = bus number
+       // BL = device/function number (bits 7-3 device, bits 2-0 function)
+       // ECX = dword read
+       mov     BX,  BDF
+       mov     di,  index
+       mov     ah,  PCI_FUNCTION_ID
+       mov     al,  READ_CONFIG_DWORD
+       int     1ah
+       mov     data, ecx
+       }
+       return data;
+   }

2. 對碟機做讀寫: INT 13

3. 設定螢幕的顏色游標什麼的: INT 10 (Watcom有很多內建的函數可以使用,使用上方便又美觀), 像我這個介面就完全是呼叫Watcom 的library做的

(待續)

2014年3月5日 星期三

UEFI C coding stytle

最近接觸UEFI的code, 她是C語言架構所組成並使用VC++或DDK來compiler,coding上跟C幾乎是一樣。但是Intel工程把C的指標發揮到淋漓盡致, coding style很漂亮,所以我寫這篇文章: UEFI C Coding style,用來練習這種coding方式

UEFI Bios 定義許的protocol夾雜許多callback function的prototype。目的是固定函數的輸入輸出型態使其成為spec的一部分,然後將protocol 傳給所需要的driver使用

我也來學學UEFI的方式寫個C程式來試試

#include <cstdio>

int add( int x, int y ) {
   return x+y;
}
int add2( int x ) {
   return x+2;
}

typedef int (*ADD_CALLBACK)(int, int);
typedef int (*ADD2_CALLBACK)(int);

//
// Protocol type of Service
//
typedef struct
{
    unsigned char rev;
    ADD_CALLBACK AddCallBack;
    ADD2_CALLBACK Add2CallBack;    
}SERVICES;

int 
main ()
{
    SERVICES gPS = {0, add, add2};
    //(&gPS)->AddCallBack=add;
    //(&gPS)->Add2CallBack=add2;
    printf("%d\n", (&gPS)->AddCallBack(1,2));
    printf("%d\n", (&gPS)->Add2CallBack(3));

   return 0;
}

2013年12月28日 星期六

C++ : virtual function

參考以下的範例,若想統一用base class pointer指向base class object以及 derived class object, 但base class 和 derived class 又有相同的函式, 那麼就必須將這種相同的函式宣告成virtual function 才能達到

#include <iostream>

class c1{
  public:
     virtual void vfunc(){ std::cout << "Calling c1\n";}
};
class c2: public c1{
  public:
     virtual void vfunc(){ std::cout << "Calling c2\n";}
};
int main()
{
  class c1 *c;
  class c1 c1_obj;
  class c2 c2_obj;
  
  c = &c1_obj;
  c->vfunc();
  
  c = &c2_obj;
  c->vfunc();
  
  return 0;
}

___________OUTPUT____________
Calling c1
Calling c2

2013年12月26日 星期四

C++ : template

function template (樣板函式):

C++提供template, 用來免去重複撰寫類似的函式(僅變數型態不同的函式)

template<class T> 
// template<typename T> //class or typename
T min (T x, T y) { 
  return (x < y) ? x : y; 
}

同樣的東西, 在C則是使用Macro來達成


#define min(x, y) (((x) < (y)) ? (x) : (y))

2013年12月25日 星期三

C++ Class 小記

這裡示範一個 Class 的 sample:

//--------------------------------------------------------------------------
//  In Tui.hpp file
//--------------------------------------------------------------------------
class CTui
{
// 沒有public的部分即為private members
public:
        CTui();  //Constructor
        ~CTui(); // De-Constructor

        void print(char *p);      

};


//--------------------------------------------------------------------------
// In Tui.cpp file
//--------------------------------------------------------------------------

#include "Tui.hpp"

//
//class members of CTui
//
CTui::CTui() 
{
  // new 記憶體, initial 參數...
}
CTui::~CTui() 
{
  // delete 記憶體
}

void CTui::print(char *p) 
{

}


2013年12月8日 星期日

C++ : class內部宣告static member

以下討論在class裡宣告static member 

static member代表他只與class相關,而不與物件相關 (故無法用this指static member)
static member有static function & static function兩種

static function 只能呼叫static variable & static function, 不可呼叫物件層級的function 和 variable。但物件層級的 function 則可同時呼叫static與非static member

請參考以下範例:


#include <stdio.h>
class cTest
{
public:
 static int Num;
 static void Func() {
  //static function 只能呼叫static variable & static function, 不可呼叫物件相關的function 和 variable member
  printf("%d", Num);
 }
};

int cTest::Num = 9; // static variable的初始值必須寫在global area. 

int main()
{
 cTest::Num = 10;
 cTest::Func();
 return 0;
}

2013年11月29日 星期五

C 巨集用法經驗談

1. 可用來設定Memory address的value。 巨集的參數記得括弧,整個巨集也要括弧以免別人引用時因為C priority問題產生bug

#include <stdio.h>

typedef unsigned int DWORD;

#define SET_MEM_32( addr, val) \
( *(DWORD* )(addr) = (val) )

#define GET_MEM_32( addr)    (*(DWORD* )(addr))

#define MODIFY_MEM_32( addr, mask, val) \
( *(DWORD* )(addr) = GET_MEM_32(addr) & ~(mask) | (val) & (mask) ) 

int 
main()
{
    unsigned char arr[10]={0,1,2,3,4,5,6,7,8,9};

    SET_MEM_32(arr, 0x22334455);
    printf("%x\n",GET_MEM_32(arr));

    MODIFY_MEM_32(arr, 0xff0000, 0x770000);
    printf("%x\n",GET_MEM_32(arr));
    
    return 0;
}

--------------執行結果--------------
22334455
22774455

2013年11月11日 星期一

C++的Container: stack使用範例

// stack.cpp
#include <iostream>
#include <stack>
#include <string>

int main()
{
    std::stack<int> ss;
    std::cout<<"size="<<ss.size()<<std::endl;
    for (int i=0; i<20; i++)
        ss.push(i);
    std::cout<<"size="<<ss.size()<<std::endl;
    while (!ss.empty()){
        std::cout << ' ' << ss.top();
        ss.pop(); //pop() has no return value, use top() to check value
    }
    std::cout<<std::endl;
    return 0;
}

輸出:


martin@martin-K42Jc:~/Code$ g++ -o stack stack.cpp

martin@martin-K42Jc:~/Code$ ./stack
size=0
size=20
 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

2013年11月2日 星期六

C++的Container: Map使用範例

C++提供map容器, [key]=value. 使用key來找尋找、插入、刪除.

map容器的排列會根據key來自動排列. (是一種平衡二元素的實現)


以下是範例:


#include <iostream>
#include <string>
#include <map>
using namespace std;
int find_and_erase(map<string, string> &mm, string ss)
{
    map<string, string>::iterator it;
    //find and erase the element
    if ( mm.end() != ( it = mm.find(ss)) ) {
        mm.erase(it); cout << ">Erase " << ss << endl;
    }else  cout << ">Cannot find " << ss << endl;
}
int show_all(string ss, map<string, string> mm)
{
    map<string, string>::iterator it;
    for(it = mm.begin(); it != mm.end(); it++)
                cout<<it->first<<" "<<it->second<<endl;
    cout << "****Finish job: "<< ss << endl;    
}

int main()
{  
    map<string, string> mm;
 
    mm["John"] = "John_data";
    mm["May"]  = "May_data";
    show_all("add John & May", mm);
    if ( false == mm.insert(pair<string, string>("Martin", "Martin_data")).second )
        cout << "(insert failed)" << endl;
    show_all("insert Martin", mm);
    // Insert same key twice, should get failed return
    if ( false == mm.insert(pair<string, string>("Martin", "Martin_data")).second )
        cout << "(insert failed)" << endl;
    show_all("insert Martin", mm);    
   
    cout << "total size: " << mm.size() << endl;
   
    find_and_erase(mm, "John");
    show_all("erase John", mm);
       
    // Reverse iterator
    for (map<string, string>::reverse_iterator itr = mm.rbegin(); itr != mm.rend(); itr++)
        cout<<itr->first<<" "<<itr->second<<endl;
    cout << "****Reverse Traversal" << endl;
    return 0;
}

Output:

John John_data
May May_data
****Finish job: add John & May
John John_data
Martin Martin_data
May May_data
****Finish job: insert Martin
(insert failed)
John John_data
Martin Martin_data
May May_data
****Finish job: insert Martin
total size: 3
>Erase John
Martin Martin_data
May May_data
****Finish job: erase John
May May_data
Martin Martin_data
****Reverse Traversal