• 締切済み

コンパイル時の静的チェックについて

次のような配列があります。 static const int ary[]={1,2,3,4,5}; この配列の要素数が5であることは、次の方法でコンパイル時にチェック出来ます。 #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) static_assert(ARRAYSIZE(ary) == 5); では、この配列で4以上の要素数が2であることをコンパイル時にチェックするにはどうしますか? 実行時であれば次のように出来ます。 assert(count_if(ary, ary+sizeof(ary), [](int i)->bool {return (i >= 4); }) == 2); 結果はコンパイル時に確定しているはずなのですが、この方法だとライブラリ関数を使用するので実行時にしかチェック出来ません。 「テスト用プロジェクトを作って...」というのも「コンパイル時に確認」ではないので無しとします。

みんなの回答

回答No.5

配列内に、「4以上」が何個あるか?って意味か。。 それだと、確かにプリプロセッサは使えないですね。 #ifでは、判定無理でした。 すいません。意味を間違えてました。

回答No.4

https://docs.microsoft.com/ja-jp/cpp/preprocessor/hash-if-hash-elif-hash-else-and-hash-endif-directives-c-cpp?view=vs-2019 んま、2にこだわる理由がよくわかりませんが、 プリプロセッサ #if ~ #else ~ #endif は、条件判断もできるので、 そこで適切な処理をすればいいかと。。 逆にこれでだめなら、答えがないような気がしなくもないですが。

katorea21
質問者

お礼

ここに挙げた例は説明用に単純化しています。実際は構造体型の配列で、その中のメンバがある値に等しい要素の数をチェックしたいのです。 #if ~ #else ~ #endifで具体的にどのように書けば出来ますか?

  • maiko04
  • ベストアンサー率17% (345/1956)
回答No.3

2==2の評価にどれほどの価値があるのでしょうか? 全く無意味ですよね。 そういうのはエラーで全て排除されます。 まぁ、最終的にはOSとかコンパイラーの性能なんですけどね。 Cの文法でエラーにしなければならないとはうたっていないと思いますので 通過する可能性はあります。

  • maiko04
  • ベストアンサー率17% (345/1956)
回答No.2

ついでに言いますと sizeof(a) == 2 というコーディングをすると 「置き換え」ですので 2==2 という文をコンパイルされてコンパイルエラーになります。 そういう意味で「置き換え」なのです。

katorea21
質問者

お礼

2==2 という文をコンパイルされるとなぜコンパイルエラーになるのでしょう? trueと評価されるだけだと思いますが。

  • maiko04
  • ベストアンサー率17% (345/1956)
回答No.1

回答ではないのですが、sizeofはコンパイル時に「確定」ではなくて 2とか5とかの数字に「置き換え」られますので実行時に変更はありえません。

katorea21
質問者

お礼

sizeofは機械語に翻訳された時点で数値に置き換えられるのは理解しています。最近まで実行時に計算されると勘違いしてましたが。

関連するQ&A

  • 引数で指定された配列の要素数の取得

    どうもこんにちは。 C言語でプログラムを作成しています。 ある関数に配列を渡すことを考えていますが、渡した配列の要素数を取得する方法は何かありますか? 標準の関数を見ても、配列の先頭アドレスのポインタとともに、配列の要素数を渡しているものばかりで、配列のポインタを渡しているものは見かけません。 要素数があらかじめわかっていれば、それを引数の型に指定できますが、呼び出されるまで不明な場合はうまくいきません。 配列の要素数も引数として一緒に渡す必要がありますか? [作ってみたサンプル] #include <stdio.h> #include <stdlib.h> #include <string.h> // func1 と func2 をまとめられないだろうか。。。 void func1(int (*p)[10]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } void func2(int (*p)[5]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } int main(int argc, char *argv[]) { ________int ary1[10] = { 2, 4, 6, 8, 0, 1, 3, 5, 7, 9 }; ________int ary2[5] = { 3, 6, 9, 12, 15 }; ________func1(&ary1); ________func2(&ary2); ________return 0; }

  • 引数が配列のときの関数内でのsizeofについて

    こんにちは. Cを勉強している最中に疑問にあったことを質問させていただきます.以下のプログラムで配列myarrayの中の最大のメンバーを見つけるプログラムです.コメントアウトしてある //int ary_size = sizeof(myarray)/4; をグローバル変数で定義するとうまく最大の数を見つけてくれるのですが, 関数の中で int ary_size = sizeof(ary)/4; と定義するとうまくいきません.そこで,以下の printf("The size of the ary is %d\n",ary_size); という表示を追加したところ,ary_size = 1となっていることが分かりました. なぜそうなるのでしょう?関数の引数はint ary[]の配列なので,sizeof(ary)でaryがメモリ中で占めるバイト数が得られるんじゃないんですかね?ちなみに私の環境ではsizeof(int)は4バイトなので int ary_size = sizeof(ary)/4; と割る4で配列のメンバーの数を求めています. 初心者の質問ですみませんがよろしくお願いします. #include <stdio.h> #include <Windows.h> int myarray[] = {1,2,3,4,5,6,7,2}; int FindMax(int ary[]); //int ary_size = sizeof(myarray)/4; int main() { int max; max = FindMax(myarray); printf("The maximum value is %d\n",max); Sleep(2000); return(0); } int FindMax(int ary[]) { int ary_size = sizeof(ary)/4; int i; int max; max = ary[0]; for(i=1;i<ary_size;i++) { if(ary[i]>max) { max = ary[i]; } } printf("The size of the ary is %d\n",ary_size); return(max); }

  • C言語のsizeof(サイズオブ)演算子について

    はじめまして。 C言語の初学者です。 sizeof(サイズオブ)演算子の理解でつまづいています。 参考書の説明は下記の通りです。 要素数を数えるのは面倒くさいので、要素数を自動的に求めて繰り返させることにします。 要素数を求める直接的な方法は用意されていませんが、計算することは出来ます。 配列全体のサイズを求め、それを要素1つのサイズで割れば要素の数がわかります。 C言語には、変数や配列のサイズを求めるsizeof(サイズオブ)演算子があります。 sizeof演算子は、次のようにして使います。 sizeof(変数や配列名) sizeof演算子には()をつけなくても良いのですが、つけた方が読みやすいでしょう。 この演算子を使って配列arrayの要素数を求めるには次のようにします。 sizeof(array) / sizeof(array[0]) 上記の説明文にある、【配列全体のサイズ】と【要素1つのサイズ】の【サイズ】とは何を指しているのでしょうか。 また、上記の【sizeof(array) / sizeof(array[0])】の割り算の意味が分かりません。 下記のプログラムを例にして、具体的に何を何で割っているのか数字を当てはめて教えてください。 よろしくお願い致します。 #include <stdio.h> int main(void) { int array[] = {42,79,13,75,19}; int i; for (i = 0;i < sizeof(array) / sizeof(array[0]);i++) { printf("array[%d] = %d\n",i,array[i]); } return 0; } このプログラムの実行結果は次の通りになります。 array[0] = 42 array[1] = 79 array[2] = 13 array[3] = 75 array[4] = 19

  • 配列要素の操作でコンパイルエラーが出ます

    JAVAの勉強中なのですが、テキストの通り入力しているのですがコンパイルエラーが出てしまいます。 public class hairetu{ public static void main(String[] args){ int[] ary = new int[7]; ary[0] =100; ary[1] = 50+31; int x = 9; ary[2] = x; ary[3] = 0; ary[3]++; ary[4] = ary[0]+ ary[1]; int j =5; ary[j] = j*2; for(int i= 0; i < ary.length; i++){ System.out.println("ary["+i+"]="ary[i]); } } } 何がおかしいのでしょうか? System.out.println("ary["+i+"]="ary[i]);の部分で、 ')'がありません。 式の開始が不正です。 ';'がありません と、エラーが出ます。 前回もテキストに説明の無いまま章末問題が出題され、解答を見ても分かりませんでした。 現在使っているテキストが信用出来なくなってきたので、 もしご存知でしたらお勧めのJAVAの入門書も教えて頂けたら幸いです。

    • ベストアンサー
    • Java
  • 配列の要素数を超えた参照のコンパイル

    C言語においては”配列の要素数を超えての参照もコンパイルエラーにはならない”という事がいえます。 例えば int a[10]={1}; とした時、a[-1] a[11]を参照しても、コンパイルエラーにはなりません。不定値が表示されるか、Red Hat Linuxに関しては”セグメンテーション違反です”とでるだけです。 しかし、わたしはCしか学んではいませんので解りませんが、配列の要素数を超えての参照はコンパイルエラーになる言語もあるのではないかと思います。 C言語はよく”暴走する言語”と言われます。規制をできる限り排除して軽くし、ミスはプログラマが取るという意味に考えています。 ”C言語においては配列の要素数を超えての参照もコンパイルエラーにはならないという事”はC言語のその様な設計思想に基ずいた仕様なのでしょうか。 それとも、違う考えに基ずいて、”配列の要素数を超えての参照もコンパイルエラーにはならない”という事に成っているのでしょうか。 宜しく願います。

  • 配列渡し後の要素数を知るには・・?

    main関数で定義した配列を他の関数で扱う場合にどうすればいいのかいまいちわかりません・・。 微妙に独学したのですが sizeofで要素数を調べたいのですがどうすればmain以外の関数内で要素数を調べる事ができるのでしょうか。私の書いたソースはこれです。 void dis(int *b){ int i, nx; nx = sizeof(b) / sizeof(b[0]); for(i=0;i<nx;i++){ printf("%d\n", *(b+i)); } } main(){ int a[5] = { 10, 20, 5, 1, -1 }; dis(a); return(0); } どうすればいいでしょうか・・・。どなたか教えていただければ光栄です。ご指導お願いします!

  • javaプログラミング

    JAVAプログラミングです。 教えてください 次のコードを実行すると、 「ary= new int[-5]; 」では例外が発生するのでtry文を用いてこの例外に対する例外処理をしたいんですがどう書けばいいですか?プログラムを実行した後に[例外処理後の実行例〕になるようにしたいです。 〔NegativeArraySizeException 例外を発生するコード〕 class Assignment9_1 { public static void main(String[] args) { int[] ary; // 例外 NegativeArraySizeException が発生 ary=new int[-5]; } } 〔例外処理前の実行結果〕 Exception in thread "main" java.lang.NegativeArraySizeException at Assignment9_1.main(Assignment9_1.java:7) 〔例外処理後の実行例〕 配列要素数の指定は負です

    • ベストアンサー
    • Java
  • ポインタの勉強中なのですが

    C言語の勉強中なのですが、ポインタのところで苦労しています。 次のような関数を作成し、main関数で実行したところ、sizeof(array)は4になりました。 main関数内で同じようにsizeof(array)を表させると配列全体のサイズが表示されますよね。 関数の仮引数として配列を書いても、実際には配列の先頭要素を指すポインタとして扱われるので 関数には&array[0]が渡され、関数は配列ひとつあたりのサイズを基に他の配列の要素のアドレスを 受け取るで合ってますよね? でもmain関数内ではsizeof(array)は配列全体のサイズを返すのに、関数内では配列ひとつあたりのサイズしか返さないのはどうしてなのでしょうか? int sum_array( int array[], int num ){ int i; int sum = 0; for( i = 0; i < num; i++ ){ sum += *(array+i); } printf("sum = %d\nsizeof(array)=%d\n",sum,sizeof(array)); return sum; }

  • C#でポインタのポインタを作りたい

    昔VC++で作ったDLLをC#で使おうと思ったのですが、なんと、その引数がint**型です。 やっていることは、intの配列がありまして、その配列の特定の要素のアドレスを納めた配列を使っています。 具体的には(型や関数記述は大まかに書きます) --------------------------------- int **array; int *item; array = calloc(10, sizeof(int)); item = calloc(1000, sizeof(int)); for (i = 0; i < 10; i++) { array[i] = item + i+100; } --------------------------------- とした、arrayを引数にしています。 これをC#から使おうとして、C#ではint**をどうするんだろうと思った次第です。 わからないのは、C#でどうやってアドレスを配列に入れるかです。 array[i] = &item[width*i] とすると、コンパイル段階で怒られてしまいますし... 知恵をお貸しください。

  • Javaのプログラムが完成出来ません・・・

    この前、大学からこんな課題が出されました。 以下の条件が含まれてるシェルソートのプログラムを作成せよ。 条件。 ・ソート済み部分に新しい値を挿入するための空き場所を作るメソッドを入れること。 ・配列の逆順数を計算するメソッドを入れる。 ・今の歩幅より一段階小さい歩幅を計算するメソッドを入れる。 ・配列の大きさに一番合った歩幅を計算するメソッドを入れる。 ・歩幅hの挿入ソートを行うメソッドを入れる。 ・シェルソートを行うメソッドを入れる。 ・mainメソッドを完成させ、ソート過程を表示しながらシェルソートを実行するようにする。 ・作成したプログラムが正しく選択ソートを実行していることが分かる実行結果を示すこと。 ・値は、 a[0]=0, a[1]=30, a[2]=20,a[3]=10 一応プログラムは、 class ShellSort{ static int compare = 0; static int copy = 0; static void showArray(int a[], int N){ //2-0:逆順数と共に配列の内容を表示するメソッド //動作:N個の要素を持つ配列aの要素を全て画面に表示する //} static void initArray(int a[], int N){ //2-0:配列にランダムな値を代入するメソッド //動作:N個の要素を持つ配列aに対し、1~Nまでの範囲の数をランダムに入れる //ただし、a[0]には常に0を入れること。 } static int shiftLargerElements(int a[], int v, int i){ //2-0:ソート済み部分に新しい値を挿入するための空き場所を // 作るメソッド //動作:配列aに対し、a[i]より手前にあるvより大きい要素を後ろ //に1つずつずらしてvを挿入するための空き場所を作る。最後に、 //できた空き場所の添え字を戻り値として返す。 //空き場所を作るまでに行った比較回数を変数compareに加算 //空き場所を作るまでに行ったコピー回数を変数copyに加算      int space = 0; int j; j = i; while((compare++ >= 0) && (a[j-1] > v)){ a[j] = a[j-1]; copy++; j--; } space = j; return space; } static int shiftLargerElements(int a[], int v, int i, int h) { //2-1:ソート済み部分に新しい値を挿入するための空き場所を // 作るメソッド //動作:配列aに対し、a[i]より手前にある要素 //a[i-h],a[i-2h],a[i-3h],...のうち、vより大きい各要素を後ろに //hだけ移動させてvを挿入するための空き場所を作る。 //最後に、できた空き場所の添え字を戻り値として返す。 //空き場所を作るまでに行った比較回数を変数compareに加算 //空き場所を作るまでに行ったコピー回数を変数copyに加算 int space = 0; return space; } 現在はここまでしか作成出来てません。 それ以降でつまづいています。 分かる人がいましたら、是非教えて下さい。