コーディング(C言語)

参考

  • Linux技術者のためのC言語入門

    ISBN-13 978-4777520657

  • 12ステップで作る組込みOS自作入門

    ISBN-13 978-4877832391

関数

  • 関数プロトタイプ宣言 function prototype declaration 戻り値の型 関数名(引数の型 仮引数名, 引数の型 仮引数名, ...)

    int test_func(int test1, int test2)
    {
        int sum;
    
        sum = test1 + test2;
    
    return sum;
    }
    
    int main()
    {
       int goukei;
    
       goukei = test_func(1, 2); /*1, 2 は実引数 */
    
       return 0;
    }
    

  • 1byte = 8bit(0x00-0xFF)
  • CPUのbitと型 コンパイラの定義による

    16bit 32bit 64bit
    char 1byte 1byte 1byte
    short 2byte 2byte 2byte
    int 2byte 4byte 4byte
    long 4byte 4byte 8byte
    long long 8byte 8byte 8byte
    pointer 2byte 4byte 8byte

構造体

ICのレジスタは構造体で定義して表す

#define SERIAL_SCI_NUM 3

#define H8_3069F_SCI0 ((volatile struct h8_3069f_sci *)0xffffb0)
#define H8_3069F_SCI1 ((volatile struct h8_3069f_sci *)0xffffb8)
#define H8_3069F_SCI2 ((volatile struct h8_3069f_sci *)0xffffc0)

struct h8_3069f_sci {
  volatile uint8 smr;
  volatile uint8 brr;
  volatile uint8 scr;
  volatile uint8 tdr;
  volatile uint8 ssr;
  volatile uint8 rdr;
  volatile uint8 scmr;
};

static struct {
  volatile struct h8_3069f_sci *sci;
} regs[SERIAL_SCI_NUM] = {
  { H8_3069F_SCI0 }, 
  { H8_3069F_SCI1 }, 
  { H8_3069F_SCI2 }, 
};

属性

  • __attribute__((__packed__)) この属性が付いた構造体は詰め物が外され,純粋に構造体のメンバ変数だけで構成されるようになります
    構造体のメンバは、メンバの先頭アドレスがバイト境界になるようにパディングが入れられる。
    構造体にpackedの属性を追加するとパディングがなくなる。
struct sample_st {
    char c;   // 1byte
    int n;    // 4byte
    void *p;  // 8byte
};

struct sample_st_packed {
    char c;   // 1byte
    int n;    // 4byte
    void *p;  // 8byte
} __attribute__ ((packed));

struct sample_st_nopad {
    char c;   // 1byte
    unsigned char pad1[3];
    int n;    // 4byte
    void *p;  // 8byte
};
  • sample_st

    address data memo
    0 C cは1byte. Cとn合わせて4byteになるように
    3byteがパディングされている
    4 n
    8 p
  • sample_st_packed

    address data memo
    0 c
    1 n cとnのメンバの間がパディングされていない
    5 p
  • sample_st_nopad

    address data memo
    0 c
    1 pad cとpad[3]で4byteになるように手動でパディング追加
    4 n
    8 p

共用体

union sample_un {
    unsigned char reg;
    struct bits {
        unsigned char bit0:1;
        unsigned char bit1:1;
        unsigned char bit2:1;
        unsigned char bit3:1;
        unsigned char bit4:1;
        unsigned char bit5:1;
        unsigned char bit6:1;
        unsigned char bit7:1;
    } regbit;
};
  • 同じアドレスに配置される
    ICのレジスタで1byteのアドレスのbit毎に機能が付加されている場合などに使用できる

    • 例 ポートデータレジスタ マイコンのGPIOのデータを制御するレジスタ
      bit毎にportの出力データを設定できる
      GPIO P17 pinをHighにしたい場合は、
      address0の7bit目を1に設定 reg.bi7 = 0x1;
      もしくは、reg = reg & 0x80;
    address bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
    0 P17 P16 P15 P14 P13 P12 P11 P10

プリプロセッサ

キーワード 説明
# 何もしない
#if, #ifdef 条件分として使う
#ifndef,#elif 条件分として使う
#else, #endif 条件分として使う
#include ヘッダファイルを取り込む
#define マクロを定義する
#undef マクロの定義を無効化する
## 前後の文字を連結する #define ___concat(a, b) a ## b
__DATE__ コンパイルの日にち
__TIME__ コンパイル時の時刻
__FILE__ ソースファイル名 printf("%s %s \n", __func__, __FILE__);
__LINE__ 行番号
  • ##の例
/* components/firmware/uboot/arch/arc/include/asm/io.h */

#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
#define clrsetbits(type, addr, clear, set) \
        out_##type((addr), (in_##type(addr) & ~(clear)) | (set))

#define out_le32(a, v)» out_arch(l, le32, a, v)
#define out_arch(type, endian, a, v)    __raw_write##type(cpu_to_##endian(v), a)
#define __raw_writel(v, c)      ({ __iowmb(); __arch_putl(v, c); })
/* マクロが続く */

C言語のプログラムの始まりと終わり

参考リンク1 参考リンク2

  • GCCプロジェクトで変数や関数を指定のセクションに配置する方法 変数や関数の宣言文に、attributeキーワードで配置先のセクション名を指定すると、指定されたセクションに変数や関数が配置されます。
    たとえば変数myVar[ ]を .mydata セクションに配置するには以下のように記述します。
    char myVar[32] __attribute__ ((section (".mydata"))) = { ... 同様に、宣言にattributeを付けることで、関数のコードを指定のセクションに置くことができます。
    また、1つのソースファイル内のデータ/コードセクションを一括して特定のセクションに配置する方法もあります。
#include <stdio.h>
#include <stdlib.h>

int count = 0;

void init1()
{
    count++;

printf("ctors test. (init1)\n");
        }

void init2()
{
    count++;
    count++;
    printf("ctors test. (init2)\n");
}

void fini1()
{
    printf("dtors test. (fini1)\n");
}

void fini2()
{
    printf("dtors test. (fini2)\n");
}

void fini3()
{
    printf("atexit test. (fini3)\n");
}

void (*fp1) (void) __attribute__((section(".ctors"))) = init1;
void (*fp2) (void) __attribute__((section(".ctors"))) = init2;
void (*fp3) (void) __attribute__((section(".dtors"))) = fini1;
void (*fp4) (void) __attribute__((section(".dtors"))) = fini2;

int main()
{
    atexit(fini3);
    printf("%d\n", count);
    exit (0);
    printf("never\n");
}
$ clang ctors.c
$ ./a.out
ctors test. (init2)
ctors test. (init1)
3
atexit test. (fini3)
dtors test. (fini1)
dtors test. (fini2)

ctorsはconstructors、dtorsはdestructors
.ctors C++用グローバルコンストラクタテーブルのセクション
.dtors C++用グローバルデスラクタテーブルのセクション