🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

1027閲覧

C言語 mallocを使えない環境でキャッシュを作る

yu_2_8_2

総合スコア34

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2019/12/08 14:18

編集2019/12/08 15:04

c言語でmallocが使えない環境(fpgaへの実装を想定、固定長配列で実装)で簡単なキャッシュを作ろうとしています。

C

1//main.c 2#include <stdlib.h> 3#include <stdio.h> 4 5#define TIMEOUT_SECOND 2 6 7#define MAXOBJ 16 8#define BUF_SIZE 10 9#define BUF_LENGTH 100 10#define INVALID_LENGTH 7 11 12int cache(char recvBuffer[BUF_LENGTH]); 13 14int intTries = 0; 15int main(int argc, char *argv[]) { 16 17 char recvBuffer1[MAX_BUFSIZE] = "bbtest"; 18 19 for (int i = 0; i < 10; ++i) { 20 int result1 = cache(recvBuffer1); 21 //int result2 = cache(recvBuffer2); 22 23 printf("result1 is : %d\n", result1); 24 25 } 26 return 0; 27} 28

C

1//cache.c 2#include <stdlib.h> 3#include <stdio.h> 4#include <time.h> 5#include <assert.h> 6 7#define MSG_FAILURE -1 8#define MAX_MSGSIZE 100 9#define MAX_BUFSIZE (MAX_MSGSIZE + 1) 10#define MAX_TRIES 5 11#define TIMEOUT_SECOND 2 12#define ARRAY_SIZE 100 13 14#define MAXOBJ 16 15#define BUF_SIZE 10 16#define BUF_LENGTH 100 17#define INVALID_LENGTH 7 18 19 20int cache(char *recvBuffer){ 21 22 //cache definition-------------------------------------------------- 23 static char *cache[BUF_SIZE]; 24 char invalid[8] = "invalid"; 25 26 static char buffer1[BUF_LENGTH] = "invalid"; 27 cache[0] = &buffer1[0]; 28 static char buffer2[BUF_LENGTH] = "invalid"; 29 cache[1] = &buffer2[0]; 30 static char buffer3[BUF_LENGTH] = "invalid"; 31 cache[2] = &buffer3[0]; 32 static char buffer4[BUF_LENGTH] = "invalid"; 33 cache[3] = &buffer4[0]; 34 static char buffer5[BUF_LENGTH] = "invalid"; 35 cache[4] = &buffer5[0]; 36 static char buffer6[BUF_LENGTH] = "invalid"; 37 cache[5] = &buffer6[0]; 38 static char buffer7[BUF_LENGTH] = "invalid"; 39 cache[6] = &buffer7[0]; 40 static char buffer8[BUF_LENGTH] = "invalid"; 41 cache[7] = &buffer8[0]; 42 static char buffer9[BUF_LENGTH] = "invalid"; 43 cache[8] = &buffer9[0]; 44 static char buffer10[BUF_LENGTH] = "invalid"; 45 cache[9] = &buffer10[0]; 46 47 //print cache----------------------------------------------------- 48 49 for (int b = 0; b < BUF_SIZE; b++) { 50 printf("Cache[%d]: ", b); 51 for (int j = 0; j <INVALID_LENGTH ; ++j) { 52 printf("%c", *(cache[b] + j)); 53 } 54 printf("\n"); 55 } 56 printf("\n-------------------------------\n"); 57 58 //ここでPutかGetかを判別する。 59 if ( *(uint16_t *)recvBuffer == 0x6262){//Put 0x6262==bb 60 61 //空いている場所を探す 62 printf("Putが実行\n"); 63 printf("recvBuffer is: %s\n", recvBuffer); 64 int flag = 1; 65 for (int d = 0; d < BUF_SIZE; d++) { 66 //cache[d]がinvalidか照合 67 for (int j = 0; j < INVALID_LENGTH; j++) { 68 if (*(cache[d] + j) != invalid[j]){ 69 flag = 0;//cache[d]は空いている 70 printf("Cache[%d]の%cは%cと一致していない\n", d, *(cache[d]+j), invalid[j]); 71 } 72 } 73 //cache[d]がinvalidのとき→現状、1つでも一致すればよくなってしまっている 74 if (flag == 1) { 75 printf("Cache[%d]はinvalid!!\n", d); 76 cache[d] = recvBuffer; //[0]にはflagが入っているため 77 //無事キャッシュに格納完了 78 break; 79 } 80 } 81 //キャッシュが満杯の時、古いのを捨てる 82 if (flag == 0) { 83 printf("cache full----------------------------------\n"); 84 cache[8] = recvBuffer; //適当に8番目を入れ替える 85 } 86 // 87 //キャッシュの中身を表示 88 printf("\n-------------------------------\n"); 89 printf("new Cache is : \n"); 90 for (int c = 0; c < BUF_SIZE; c++) { 91 printf("Cache[%d]: ", c); 92 for (int j = 0; j < INVALID_LENGTH; ++j) { 93 printf("%c", *(cache[c] + j)); 94 } 95 printf("\n"); 96 } 97 return 0;//Putなので返すものはない 98 //------------------------------------- 99 } else if(*(uint16_t *)recvBuffer == 0x6161){ //Getのとき 0x6161==aa 100 printf("Getが実行\n"); 101 for (int i = 0; i < BUF_SIZE; i++) { 102 if (recvBuffer[i+1] == *cache[i]) { 103 printf("Cache Hit!"); 104 return 1; //Cache hitのときは1を返すようにする 105 break; 106 //sendBuffer_fromserver[0] = '1'; 107 } 108 } 109 //for文が最後まで実装されたらキャッシュミス 110 printf("Cache Miss!\n"); 111 return 2; //cache miss のときは2を返すようにする 112 } 113}

上のプログラムを取り敢えず作成したのですが、main中で「cache」を呼び出すとそのたびに

C

1char *cache[BUF_SIZE];

をしてしまうのでやはり毎回初期化されてしまっています。
main中でcache[BUF_SIZE]をしたいのですが、いろいろ試行錯誤してもうまくいきませんでした。。

どなたか解決策を思いつく方ご教授頂けると幸いです。


現在の進捗

C

1char *cache[BUF_SIZE];

C

1static char *cache[BUF_SIZE];

に修正。

C

1for (int a = 0; a < BUF_SIZE; a++) { 2char buffer[BUF_LENGTH] = "invalid"; 3cache[a] = &buffer[0]; 4}

C

1static char *cache[BUF_SIZE]; 2 char invalid[8] = "invalid"; 3 4 static char buffer1[BUF_LENGTH] = "invalid"; 5 cache[0] = &buffer1[0]; 6 static char buffer2[BUF_LENGTH] = "invalid"; 7 cache[1] = &buffer2[0]; 8 static char buffer3[BUF_LENGTH] = "invalid"; 9 cache[2] = &buffer3[0]; 10 static char buffer4[BUF_LENGTH] = "invalid"; 11 cache[3] = &buffer4[0]; 12 static char buffer5[BUF_LENGTH] = "invalid"; 13 cache[4] = &buffer5[0]; 14 static char buffer6[BUF_LENGTH] = "invalid"; 15 cache[5] = &buffer6[0]; 16 static char buffer7[BUF_LENGTH] = "invalid"; 17 cache[6] = &buffer7[0]; 18 static char buffer8[BUF_LENGTH] = "invalid"; 19 cache[7] = &buffer8[0]; 20 static char buffer9[BUF_LENGTH] = "invalid"; 21 cache[8] = &buffer9[0]; 22 static char buffer10[BUF_LENGTH] = "invalid"; 23 cache[9] = &buffer10[0];

に書き下し。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2019/12/08 15:03

どういう動きをさせようとしているのか, コーディングが合っているのか間違っているのかが不明な個所が多く, 読み取れません. どのような仕様でしょうか. パラメータのポインタを直値と比較していますが, FPGA に入れないと単体テストも出来ないということでしょうか.
yu_2_8_2

2019/12/08 15:30

ご回答ありがとうございます。情報不足の質問となってしまっており申し訳ありません。 FPGAに入れないと単体テストが出来ないわけではなく、現段階ではキャッシュ部分のみの実装をしております。 仕様といたしましては、[BUF_SIZE]個を保持するキャッシュで、それぞれサイズ[BUF_LENGTH]の文字列を格納するものを作りたいです。 現在、main中ではキャッシュに文字列を挿入する際しか実装していませんが、 キャッシュに文字列を挿入する際には0を返し、 ある文字列と同じ文字列がキャッシュ中に存在していれば1を返す、 なければ0を返すようにしています。 キャッシュへの挿入/キャッシュ中に存在するかの確認は文字列の最初の2文字(aaかbbか)で判別するようにしています。 お手数おかけしますがどうぞよろしくお願いいたします。
jimbe

2019/12/08 19:27

> 文字列の最初の2文字(aaかbbか)で判別 失礼しました, ポインタと直値の比較に見えたのは文字列だったのですね. 勘違いでした. ところで, ヒットしたかを返すのはともかく, 挿入か確認かでデータを変えるという仕様はあるのでしょうか. キャッシュというと, 有るかを確認し, 有ればそれを返し, 無ければ挿入した上でそれを返す…というイメージなのですが.
guest

回答4

0

ベストアンサー

Compile and Execute C Online (GNU GCC v7.1.1) でテストしました.
若干(?)仕様を変えています.

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define BUF_SIZE 3 //テストのために少なく 6#define BUF_LENGTH 100 7 8static char *cacheLine[BUF_SIZE]; 9static char cacheBuffer[BUF_SIZE][BUF_LENGTH]; 10 11void initCache() { 12 for(int i=0; i<BUF_SIZE; i++) { 13 cacheLine[i] = cacheBuffer[i]; 14 *cacheLine[i] = '\0'; 15 } 16} 17 18int cache(const char *data) { 19 int result = 2; //無かった->上書き追加 20 int i; 21 for(i=0; i<BUF_SIZE; i++) { 22 if(*cacheLine[i] == '\0') { 23 result = 1; //無かった->新規追加 24 break; 25 } else if(strcmp(cacheLine[i], data) == 0) { 26 result = 0; //有った 27 break; 28 } 29 } 30 if(result == 2) i = BUF_SIZE-1; 31 if(result != 0) strcpy(cacheLine[i], data); 32 if(i > 0) { 33 char *p = cacheLine[i]; 34 for(; i>0; i--) cacheLine[i] = cacheLine[i-1]; 35 cacheLine[0] = p; 36 } 37 return result; 38} 39 40//キャッシュの中身を表示 41void printCache() { 42 printf("- cache -------------\n"); 43 for(int i=0; i<BUF_SIZE; i++) { 44 printf("%d: ", i); 45 printf(*cacheLine[i]=='\0'?"(invalid)":"'%s'", cacheLine[i]); 46 printf("\n"); 47 } 48 printf("---------------------\n"); 49} 50 51int main() { 52 char *testdatas[] = { "test","data","abc","0123456789","qwerty" }; 53 initCache(); 54 srand((unsigned int)time(NULL)); 55 for(int i=0; i<10; i++) { 56 char *data = testdatas[rand()%5]; 57 int result = cache(data); 58 printf("str='%s' result=%d\n", data, result); 59 } 60 printCache(); 61 return 0; 62}

text

1str='test' result=1 2str='qwerty' result=1 3str='qwerty' result=0 4str='abc' result=1 5str='abc' result=0 6str='0123456789' result=2 7str='abc' result=0 8str='test' result=2 9str='abc' result=0 10str='abc' result=0 11- cache ------------- 120: 'abc' 131: 'test' 142: '0123456789' 15---------------------

投稿2019/12/08 20:47

編集2019/12/08 20:56
jimbe

総合スコア13202

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

char *cache[BUF_SIZE];

ローカル変数で、ポインタの配列を宣言してますが、これでいいのですか?

for (int a = 0; a < BUF_SIZE; a++) {
char buffer[BUF_LENGTH] = "invalid"; cache[a] = &buffer[0]; }

このbufferという配列はこのfor文を抜けると無効になりますが、これでいいのですか?
また、&buffer[0];のアドレス値はいくらループさせようと同一値ですが、これでいいのですか?

他にもいろいろありますが。。

投稿2019/12/08 14:41

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yu_2_8_2

2019/12/08 15:06

ご回答ありがとうございます。ご指摘の通り、 char *cache[BUF_SIZE]; を static char *cache[BUF_SIZE]; に、 上記for文を取り払ってみたのですが未だ上手くいきません。 できましたらその他の問題点も教えていただけますか?
yumetodo

2019/12/08 17:16

>ローカル変数で、ポインタの配列を宣言してますが、これでいいのですか? がスルーされているのはこれで意図した挙動ということですかね?本当に?
y_waiwai

2019/12/08 23:41

最後のソースコードですが、それのすべての配列はローカル変数ですが、 ローカル変数というのは、その関数が終了すると開放、消滅してしまいます。 その配列をその関数の中だけで使うならそんでいいですけど、あなたのやりたいことはそれでいいんでしょうか
guest

0

main中で「cache」を呼び出すとそのたびに
char *cache[BUF_SIZE];
をしてしまうのでやはり毎回初期化されてしまっています

「そのたびに char *cache[BUF_SIZE]; をしてしまう」はC言語プログラマが語る日本語として意味不明・いかがなものか?と思いますが、私は質問者の気持ちをこう想像します。

cache() 関数が持つデータを、一回目の呼出しの時だけ初期化したい。
二回目の呼出し以降では、初期化せず、前回の値を引き続き使いたい。
それができないなら、せめて main() から一回だけ初期化処理を呼び出すようにしたい。

cache() 関数が持つべきデータとは、次の2種類のようです。

  • char buffer1[]〜buffer10[]、10個の文字型(char型?)配列
  • char *cache[BUF_SIZE]、即ち要素数10個のポインタ配列

cache() 関数の中に、初期化済みか否かを示す static なフラグ変数を設けるのが定石じゃないでしょうか。そうすれば main() から初期化関数を呼ぶ必要はなくなります。質問者は一回だけ初期化したいものが何か分かってるでしょうから、細かくは書きませんが、

C

1int cache(char *recvBuffer) 2{ 3 static int needInitialize = 1; // 要初期化フラグ 4 5 if (needInitialize == 1) { // 未初期化?なら 6 needInitialize = 0; // 初期化済みにする 7 8 // 以下に、一回だけ初期化したいことを列挙する 9 cache[0] = &buffer1[0]; // 一回だけ初期化したいのは、これ? 10 } 11 // 以下は、呼びだされた時の通常処理

初期化について。
cache[0] = &buffer1[0]; ですが、&buffer1[0] は配列の先頭アドレスですから配列名だけで cache[0] = buffer1; と書けます。
さらに、buffer1[] 〜 buffer10[] は **static な配列ですから、これらの先頭アドレス10個はリンク時に確定する「定数」**です。よって、次のように書いて最初から初期化できます。

C

1 static char buffer1[BUF_LENGTH] = "invalid"; 2 // (途中省略) 3 static char buffer10[BUF_LENGTH] = "invalid"; 4 static char *cache[BUF_SIZE] = { 5 // 最初から初期化してしまえ 6 buffer1, buffer2, buffer3, buffer4, buffer5, 7 buffer6, buffer7, buffer8, buffer9, buffer10, 8 };

これで、上に書いた要初期化フラグを使うことなく、実行開始時に初期化が済んでしまうので、これだけで解決する可能性もあります。
少なくともPutとGetの対応が取れていない。初期化だけの問題じゃないね。先は長そうだw


ボンクラでも大体わかりましたw。以下、感想です。答えなくても良いから考えてみて。

  • コンパイルエラーが出ない程度には書ける。この段階では悪くない。
  • でもやろうとしていることがヘン。データ構造、cache() 関数が何を返すか等、再考したほうが良い。
  • キャッシュ中に見つかったエントリを、今後どう使いたいのか。
  • エントリが空いてる・使っているの区別の付け方、エントリの探し方がいまいち重たい・分かりにくい・(バグってる?)感じ。
  • cache()に渡す文字列の先頭2文字でput・getを指定するって、どうなの?その2文字も一緒にキャッシュするの?今のコードだとputした文字列を絶対探せない感じになってる。
  • 素直なやり方は、もうひとつ引数を設けてput・getの操作を指定するか、put関数・get関数に分けるか、だと思う。関数を分ければ初期化関数は簡単に書ける。
  • malloc() が使えたとしたら、どうしたかったのだろうか。
  • キャッシュするデータが文字列なら <string.h> 系の strcmp(), strcpy() などを使うとか。
  • 文字列なら "%c" 表示を繰り返すのでなく、"%s" で一気に表示しちゃえばすっきりするのに。

投稿2019/12/09 02:08

編集2019/12/09 04:36
rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2019/12/09 03:01

Cの書き方が不慣れな上に、ロジックがアヤシイ感じw
guest

0

詳しく見てないですがstatic変数ではだめなのですか?

投稿2019/12/08 14:21

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yu_2_8_2

2019/12/08 14:36

char *cache[BUF_SIZE]; を static char *cache[BUF_SIZE]; にしてもうまくいきませんでした。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問