【C言語】よく分からないクソコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <stdio.h> #include <string.h> int main(void) { int x = 1919; // x座標 int y = 4545; // y座標 char str1[10] = ""; char str2[10] = ""; sprintf(str1, "%d", x); // x座標を文字列に変換 sprintf(str2, "%d", y); // y座標を文字列に変換 strcat(str1, " "); // x座標の後に空白を追加 strcat(str1, str2); // y座標を追加 puts(str1); return 0; } |
最近演習中に発掘されたクソコードだ。
x
とy
が定数だが、実際にはWin32 APIを使ったプログラム中で、ウィンドウ中に描画する画像の座標が入る。
また、この座標はユーザの操作で変化する。
まず、どのへんがクソコードなのかと言うと、1番目につくのはsprintf()
の使い方だ。
実際にコメントにはint
を文字列に変換すると書いてあるし、演習中でも各種変数を文字列に変換する関数という扱いだった。
確かにそのような使い方もできるが、明らかに1回のsprintf()
で済ませられるのだからもっと簡潔にするべきだ。
ちなみに、char []
型変数は1つで十分だが、なぜか2つ必要らしい。なぜだか知らないが!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> #include <string.h> int main(void) { int x = 1919; // x座標 int y = 4545; // y座標 char str1[10] = ""; sprintf(str1, "%d %d", x, y); puts(str1); return 0; } |
sprintf()
を1つだけにするとこうなる。
むしろこういう使い方のほうが自然な気がするが一体どういう意図でこうしなかったのか本当に分からない。
使い方もprintf()
と似ているし、違うのは出力先が文字列か標準出力かということくらいだというのに。
それともう1つ。
x座標とy座標はウィンドウ上の画像の位置で、ウィンドウの大きさなんて4桁×4桁までなのでchar []
は10バイトで十分らしい。
確かに今のディスプレイの解像度を考えると十分だと思う。
しかし、座標には負の値が入ることがある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <stdio.h> #include <string.h> int main(void) { int x = 1919; // x座標 int y = -4545; // y座標 char str1[10] = ""; char str2[10] = ""; sprintf(str1, "%d", x); // x座標を文字列に変換 sprintf(str2, "%d", y); // y座標を文字列に変換 strcat(str1, " "); // x座標の後に空白を追加 strcat(str1, str2); // ここでバッファオーバーフロー puts(str1); return 0; } |
2回目のstrcat()
でバッファオーバーフローを起こしている。
このクソコードはC言語のメモリ管理の大変さを思い知らせるためだったのか?
このクソコードに対し、どのような魔改造改良をしていくべきか。
注目すべきはC言語やってるつもりなのにC++としてソースコードをコンパイルするというのが当たり前になっている大学のやり方だ。
つまり、C++が使えるということだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <sstream> int main(void) { using namespace std; int x = 1919; // x座標 int y = -4545; // y座標 stringstream ss; ss << x << " " << y; cout << ss.str() << endl; return 0; } |
こんなことstd::stringstream
クラスで一瞬で終わる。
std::string::c_str()
とstd::string::length()
があればC言語の関数に文字列渡すのも全く問題ない。