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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

9回答

1982閲覧

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

yowashi

総合スコア19

C

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

1グッド

0クリップ

投稿2017/07/06 08:29

編集2017/07/06 23:24

お世話になります。

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

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

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

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

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

追記

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

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

LouiS0616👍を押しています

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

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

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

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

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

guest

回答9

0

ベストアンサー

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

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

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

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


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

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

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

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

投稿2017/07/06 09:06

yohhoy

総合スコア6191

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

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

0

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

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

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

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

c

1#define FLAG1 (0x01) 2#define FLAG2 (0x02) 3#define FLAG3 (0x04) 4#define FLAG4 (0x08) 5#define FLAG5 (0x10) 6#define FLAG6 (0x20) 7#define FLAG7 (0x40) 8#define FLAG8 (0x80) 9 10if (v & FLAG1) { 11 // FLAG1 は ON だ 12}

これがプログラムの中に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 08:57

編集2017/07/07 00:00
mattn

総合スコア5030

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

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

momon-ga

2017/07/06 09:10

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

2017/07/06 10:09

> しかし古くからプログラミング言語を触っている人であれば、ビットフラグを使って1バイトしか使わない様にします。 これは必ずしもそうでもないですよ。 一般にパックすると遅くなりますから、速度とメモリのトレードオフから適切な方法を選択します。
mattn

2017/07/06 10:20

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

2017/07/06 16:48

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

0

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

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

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

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

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

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

投稿2017/07/06 16:59

編集2017/07/06 17:04
yumetodo

総合スコア5850

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

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

0

こんにちは。

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

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

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

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

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

投稿2017/07/06 10:25

Chironian

総合スコア23272

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

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

0

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

投稿2017/07/06 08:49

編集2017/07/06 08:50
ttyp03

総合スコア16998

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

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

0

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

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

投稿2017/07/06 18:36

mugicya

総合スコア1046

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

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

0

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

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

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

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

投稿2017/07/06 08:43

PineMatsu

総合スコア3579

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

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

0

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

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

C

1#include <stdio.h> 2#include <stdlib.h> // for atoi(), atol() etc. 3int main(void) 4{ 5 char arr[] = { '3', '5', '\0' }; 6 int num; 7 8 num = atoi(arr); 9 printf("%d\n", num); // "35" が表示される

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

C

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

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

C

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

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

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

  1. 変数・配列に必要なメモリサイズの違い

これは、机上で・静的に・簡単に計算・予測でき、初心者でも可能な事です。

  1. コンパイルされた機械語のサイズの違い

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

  1. 実行時間、動作クロック数の違い

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

投稿2017/07/07 00:21

rubato6809

総合スコア1380

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

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

0

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

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

投稿2017/07/06 08:54

tacsheaven

総合スコア13703

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問