質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

89.98%

メモリや変数宣言の際の意識改善

解決済

回答 9

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,983

yowashi

score 15

お世話になります。

聞きたいことから話しますと、
どのような事柄やプログラムコード、アルゴリズムから省メモリの意識を持ちましたか?
char や short int等、特にcharなど可動範囲の意識をどのようにして培いましたか?
よろしければアドバイスお願いいたします。

以前の質問で変数の型を意識してコードを作ることを考えてきましたが、いろいろなサイトの入門問題を解いていく中で、いまいち、使用メモリを少なくする意識というのが培われません。

もちろん、10できるものが5の容量でできたら残りの5に他の機能を加えられるという、商品価値として表面的には意識しています。

それでも、特にchar型が疑問なのですが、文字を扱う際のchar型は今の段階で理解できているつもりです。
ただ、数字の可動範囲が255までだから、charですむでしょ、というような考えがいまいち持てずにいます。
単純なインクリメント、デクリメントはできまずが、演算をする際には文字コードから数値に直したりと初心者としては頭を使います。
atoiなどの関数を使用して数値に変換できますが、そこまでしてcharで宣言するべきなのか悩みます。

自分が実際に商品に関わったことがないので1バイトの重みが理解できていない、もしくはcharや型への認識が甘い、というのが一番なところなんでしょうが笑

追記

回答ありがとうございました。charもろもろ、どの段階でそういう意識がついたのか、自分の中でふむふむ(@_@)となったものをBAにさせていただきました。

ただ、今の環境でそこまで意識しなくてもいいこと、バグの発生の可能性を小さくする、他の機器とあわせたときの差を小さくするなどの観点からメモリを全く意識しなくてもいいかというとそうではないことが表面的にではありますが、理解が深まりました。
改めて、テーマを決めてプログラムに触れてみようと思います。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 9

checkベストアンサー

+7

どのような事柄やプログラムコード、アルゴリズムから省メモリの意識を持ちましたか?

動的メモリ確保(malloc)失敗に直面すると、イヤでも意識することになります(笑

ただし、一般的なサーバ/PC環境で省メモリプログラミングを意識的する場面はほとんど無いはずです。一方、組込機器などコンピューティングリソースに制限が強い分野では、省メモリは依然として重要なテーマかと思います。

“省メモリ”という観点では、書籍「省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集」がおすすめです。


それでも、特にchar型が疑問なのですが、文字を扱う際のchar型は今の段階で理解できているつもりです。
[...]
atoiなどの関数を使用して数値に変換できますが、そこまでしてcharで宣言するべきなのか悩みます。 

「扱う値範囲が小さいから」という理由だけでchar型を選択するのは、メリットよりもデメリットが大きいため避けるべきです。C言語の場合、整数値の計算過程では必ずint型となるため、int型より小さい整数型の扱いには注意が必要です。

数個程度のローカル変数では、意図的にchar型やshort型を選択しても省メモリ効果はほとんどありませんし、むしろ型変換のために実行速度が低下したりします。

例外として、大量のデータを扱う配列型ならば小さな型を利用すると大きな省メモリ効果を見込めます。(例:画像ピクセルデータなどはunsigned char型の配列として保持されますし、音声波形データはshort型配列として保持されます)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+7

そのプログラムが動作する環境に依存しますし、どこまで汎用的で品質の高いソフトウェアを作るかという意識の問題かと思います。

今もなお、組み込み用途ですととにかくメモリが足りません。またメモリを沢山積んでいる環境であっても、その富豪さに溺れて沢山のデータを処理しようとします。

例えば独立した値を保持できるフラグが8つ必要になったとします。ある人は int の変数を8つ使うかもしれませんし、ある人は char の変数を8つ使うかもしれません。

しかし古くからプログラミング言語を触っている人であれば、ビットフラグを使って1バイトしか使わない様にします。

#define FLAG1 (0x01)
#define FLAG2 (0x02)
#define FLAG3 (0x04)
#define FLAG4 (0x08)
#define FLAG5 (0x10)
#define FLAG6 (0x20)
#define FLAG7 (0x40)
#define FLAG8 (0x80)

if (v & FLAG1) {
  // FLAG1 は ON だ
}

これがプログラムの中に1つや2つしかない種類のフラグなので特に問題にならないのですが、例えばこのフラグが構造体の中にあり、さらにその構造体の配列が100万レコードあったと考えて下さい。

int で 8 つのフラグを作った人は

4 * 8 * 1000000 = 32MB

char で 8 つのフラグを作った人は

1 * 8 * 1000000 = 8MB

ビットフラグで で 8 つのフラグを作った人は

1 * 1000000 = 1MB

実際にはこのフラグ以外の情報も構造体に乗せる事になるので、もう少し結果は異なります。
数十MB しか乗らない環境でプログラムを動かさないといけない環境で 32MB もメモリを取ってしまったらそれだけでクラッシュしそうですね。

ただもう 2017 年です。メモリもそんなに高くありません。沢山メモリを積んでいるからそんな事考えるの勿体ないと思われる事も多くなりました。僕も富豪的にメモリを取る事はあります。
作ったソフトウェアのユーザが100万レコード引っ張る使い方をするのか、1億レコード引っ張る使い方をするのか、それは分かりません。
万が一の時を想定してメモリをそれほど取らない作り方をしておくと、長く愛されるソフトウェアになるかもしれませんね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/06 18:10

    大量データを扱う(バッチ処理)ときと、常駐アプリを作ると意識しやすいかもですね。

    キャンセル

  • 2017/07/06 19:09

    > しかし古くからプログラミング言語を触っている人であれば、ビットフラグを使って1バイトしか使わない様にします。

    これは必ずしもそうでもないですよ。
    一般にパックすると遅くなりますから、速度とメモリのトレードオフから適切な方法を選択します。

    キャンセル

  • 2017/07/06 19:20

    確かに符合拡張のコードが吐かれるでしょうから少し遅くなりますね。用途次第ですね。

    キャンセル

  • 2017/07/07 01:48

    また近年の並列処理化にビットフラグは相容れないのでやはり注意が必要です。

    キャンセル

+3

今の時代のハードはリソースに余裕があるので、あまり省メモリこだわる必要はないと思います。
それよりは、その変数の用途としての範囲はどれくらいなのか、符号があるのかないのかを明確にコーディングするべきかと思います。
そのためには型を正確に定義してあげることだと思います。
そうしておくことで、想定外の値を代入しようとしてしまった場合、コンパイルのタイミングで警告されるので事前にバグが防げます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+3

こんにちは。

どのような事柄やプログラムコード、アルゴリズムから省メモリの意識を持ちましたか?

私自身はまだまだメモリが非常に高価だった時代から携わってきたので、結構節約には気を使います。1KBytesあればまだ良い方で256バイトのメモリをどう使うか結構頭を絞ることもありました。

でも、メモリをギチギチにすると生産性がかなり劣化します。ですので、メモリに余裕がある時は生産性の方を優先し、多少無駄なメモリの消費を許容します。

PCの場合は、数値を記録する時は通常はint型を使います。shortを使うケースはかなり稀ですね。まして、charは文字を記録するためにしか使いません。
高々数十バイトを頑張って節約するのは虚しいです。
gccはサブルーチン呼び出しの度にスタックを16バイトの倍数に調整します。
その環境で数バイト節約しても仕方がないでしょう。

malloc等でメモリ確保する時は結構大きなメモリをボコンと確保できるのでちょっと気を使います。意味もなく(プログラムを簡単にするとか高速にするような効果もないのに)多量のメモリを確保していないかは気にします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+3

まずC/C++は変数の大きさについてほとんど規定の無い言語なので、型サイズを意識するときは必ずstdint.h/cstdint[u]intN_t型を利用します。

近年メモリーは潤沢になって湯水の如く使っても問題にならないことが多いですが、組み込み系以外では全く意識しなくていいかというとそうでもありません。

ムーアの法則に従い性能が向上するCPUに対しメモリーの速度はDDR4を持ってしても圧倒的に遅いのでのL1-L3キャッシュに乗るかと言うのは大事な要素です。メモリー律速な処理については時にはキャッシュを意識してあげないといけません。キャッシュに載せるために、不必要に大きな型を利用しないことはあります。

また動的確保の場合、連続したメモリー領域を要求しますのであんまりに大きいと(1GBこえたり)OSが確保に失敗することがあります  
ref: rigayaの日記兼メモ帳 自動フィールドシフト 高速化版+13#comment2520

ただ覚えておきたいのは、整数演算はintに変換しようとします(integral promotion)。なのでただの整数演算でintではない型を利用する意義はないと思われます。

結論としてはよほどメモリー制約が大きい環境を除いては気にすることはないと思います。きっと他にもっと気にしないといけないことがあります。計算量の削減とかメモリーアクセスパターンとか動的確保の回数を減らすとかな。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

昔、組み込み系の8bit CPUなどでメモリが16KByteだとか32KByteとかしかない時代は、それこそメモリを如何に切り詰めて作るかということをやってました。当然アセンブラで記述してました。(ROM+RAMあわせて64KByteの時代ですからね^^;)

が、今は、パソコンで動かす場合は意識するのはメモリーリークくらいで、そういうことに注力するより、メンテナンスのしやすさや冗長性を上げることが主眼になっています。

マイコンボードのプログラム作ったりもしますが、昔に比べればMByteオーダーでメモリがあるので、大規模なプログラムでない限り余り気にしないですね。

プログラムの処理内容にもよりますが、速度重視ならそういう作りを、通信系でデータの授受を少なくしてオーバーヘッドを小さくしたい場合は、そういうことを意識して作ったりはします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

限られたROM容量でプログラムを組んできた。位ですかね。
組み込み系とかで仕事していると、設計がアレだと容量オーバーで乗りません。
普通のWindowsとかだと、特に気にしなくてもいい気がします。
そりゃ、データが何ギガもあるような物だと、色々工夫が必要になりますが。
フラグを持ったデータ構造でも、組み込み系ならバイトデータの1ビットをフラグにしたりしますが、
気にしなくていい環境なら、構造体にboolean とか平気で使用したりします。

昔からやってる人の中には、データを小さくする事に快感を覚える方も少なからずおりますがw
一度自分で容量上限(データファイル含む)を決めてアプリを作成してみては?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

現在の業界で、メモリサイズを意識しなくてはならないようなシビアな環境というのは、組み込み系以外にはまずありません。
最近の言語だと動的型付けをするのでそもそも意識できない(させてくれない)場合もありますし。

ただ、ガベージコレクションを実装している環境だと、意図しないタイミングでのガベージコレクションでシステムが止まることもあるので、それを避けるという意味で使用しているメモリの総量を意識することはありますね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

atoiなどの関数を使用して数値に変換できますが、そこまでしてcharで宣言するべきなのか

ここで atoi() に言及されたのは、atoi()について質問者に勘違いがある事を示唆します。
atoi() は、例えば次のようなプログラムで使い方を確認できます。

#include <stdio.h>
#include <stdlib.h>    // for atoi(), atol() etc.
int main(void)
{
    char arr[] = { '3', '5', '\0' };
    int num;

    num = atoi(arr);
    printf("%d\n", num);    // "35" が表示される


念の為:atoi() は、数字文字列を数値(整数)に変換する関数です。引数はあくまで数字文字列、即ちchar型の「配列」であって、char型の「変数」ではありません。例えば、

    char a = 35;
    ++a;
    printf("%d\n", a);


ここまでは良いが、次の3行はいずれも間違いです。

    num = atoi(a);
    a = atoi(a) + 1;        // 1 増やしたい?
    printf("%d\n", atoi(arr[1]));    // '5' を表示したい?


普通コンパイラが警告を発します(実行すれば異常終了?)ので、間違いに気づくでしょうが、こうした使い方を想定したのでは、と老婆心(老爺心?)ながら思った次第。
ちなみに、printf("%d\n", a);では、aの値がchar型からint型へと型変換が行われます。その分、機械語コードも実行時間も増える・・・まあほんの微々たるものですけどね。

既にベストアンサーが決まってますので、私から一つアドバイスを。変数・配列をintにした場合とcharにした場合で、どれだけ違うか、数値化して比較する、そういう習慣をつけたら、いかがですか?少なくとも一度、深く比較検討する経験をしてみるとか。

  1. 変数・配列に必要なメモリサイズの違い
    これは、机上で・静的に・簡単に計算・予測でき、初心者でも可能な事です。

  2. コンパイルされた機械語のサイズの違い
    その気になれば調べられます。ただ、最終的な実行形式ファイルのサイズを比較しても正確な比較検討にならない可能性があります。アセンブリコードで比較すると正確に比較・検討できます。つまり中級以上の技術が必要になるでしょう。

  3. 実行時間、動作クロック数の違い
    これは最近のプロセッサだと、実は私も困難(苦笑)、動作クロックを調べるための資料探しから始めなきゃならない。正確に見積もるには、コアな部分に関して深い理解が必要です。
    ただ、注目する変数をアクセスする箇所が(膨大なほど)たくさんあれば、実際の実行時間を計測して、どれだけ違うか傾向が見えてくる可能性はあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 89.98%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る