ページ 1 / 1
無題
Posted: 2009年5月26日(火) 18:33
by 研修生
空白の列を同じスペーシングを行なう最少の数のタブおよびブランクで置き換えるプログラム
を作成していまして、下記のように完成しました。
#include "stdafx.h"
#define TABSTOP 4
void put_tab_and_space(int num_tab, int num_blank);
int main(int argc, char* argv[/url])
{
int c, ntab, nblank, pos;
nblank = 0;
ntab = 0;
pos = 0;
while((c = getchar()) != EOF){
if(c == ' '){
pos++;
if(pos % TABSTOP != 0){
nblank++;
}
else{
nblank = 0;
ntab++;
}
}
else{
put_tab_and_space(ntab, nblank);
ntab = 0;
nblank = 0;
putchar(c);
if(c == '\n'){
pos = 0;
}
else{
pos++;
}
}
}
put_tab_and_space(ntab, nblank);
return 0;
}
void put_tab_and_space(int num_tab, int num_blank)
{
int i;
for(i = 0; i < num_tab; i++){
putchar('\t');
}
for(i = 0; i < num_blank; i++){
putchar(' ');
}
}
これをCのソースファイルに適用すると(上記のプログラムではタブを考慮していないのでファイル内にあるタブは空白で置き換えます)
変換前のソースコードと変換後では見た目上は瓜二つですが
文字列や文字定数を特別処理しないとソースコードとしては同じものにならないとか言われたのですが
まるで同じにしか見えません。これについてわかる方いませんか?
Re:無題
Posted: 2009年5月26日(火) 18:39
by 御津凪
文字列・文字定数の中にも空白がある場合、そこを置き換えられてしまったらコードは違うものになります。
Re:無題
Posted: 2009年5月26日(火) 18:43
by 研修生
それはどうしてです? その理由が知りたいのです。
Re:無題
Posted: 2009年5月26日(火) 19:02
by 御津凪
int main(){
printf( " 1\n" );
printf( " 2\n" );
printf( " 3\n" );
printf( " 4\n" );
return 0;
}
というようなソース上でインデント整形済みの文字列があるコードがあったとします。
(文字列の空白は半角スペース)
これを研修生さんのコードで適用すると、適用後のコンパイル・実行結果は、
崩れた形で出力されてしまいます。
(適用元のタブの長さが4で指定されていて、出力先が4以外の場合、さらにずれます)
また、
putchar ( ' ' );
と、半角含みのコードなどの原因で ' ' がタブ文字に置き換えられてしまったら
半角スペースの出力ではなく、タブ文字の出力になってしまいます。
条件式でこのような影響のある置き換えが起これば、
もちろん正しい(同じ)プログラムコードではなくなります。
Re:無題
Posted: 2009年5月26日(火) 19:19
by 研修生
int main(){
printf( " 1\n" );
printf( " 2\n" );
printf( " 3\n" );
printf( " 4\n" );
return 0;
}
を適用してもまるで同じになります。
おそらくファイル内のタブを空白に変換してないのでは?
このプログラムではタブが認識できないので・・
変換せずに適用するとインデントが崩れます。
Re:無題
Posted: 2009年5月26日(火) 19:38
by 御津凪
上に書いたことは
"変換を適用したソースコードをコンパイルして実行した時のコンソールの出力"
についてです。
変換の適用前と適用後のソースコードを実行して比べてみましたか?
Re:無題
Posted: 2009年5月27日(水) 09:33
by 研修生
うーんわからないですね。実行してみましたが確かにずれますがインデントがずれるのはやはりタブ関係が原因にしか見えない。文字定数と文字列が問題とのことですから・・
Re:無題
Posted: 2009年5月27日(水) 10:27
by 御津凪
> 文字定数と文字列が問題とのことですから・・
これは、
> 実行してみましたが確かにずれますが…
ということです。
ただし、変換時にタブを考慮していないのが原因ではなく、プログラムで使う文字列・文字定数自体に
置き換え処理が行われる可能性があるからです。
" "
↑は空白4文字(+終端文字)の5バイトの文字列を示していますが、
この空白4文字がタブ文字に置き換えられてしまったら、
タブ1文字の(+終端文字)の2バイトの文字列に変わってしまいます。
よって、文字列・文字定数の中身の文字は変換しないように特別処理しないといけないという意味です。
もしこれでもわからなかったら、
(こちらからは散々似た様な回答をしているので)
> 文字列や文字定数を特別処理しないとソースコードとしては同じものにならない
といわれた方にもう少し詳しい意味(ソースコードとしては同じものにならないのはなぜか)を聞いてください。
というより聞いたほうが早かったかもしれませんが…
Re:無題
Posted: 2009年5月27日(水) 10:31
by Mist
こういう例だとわかるでしょうか。
strcmpでstrという文字配列に空白4個が入っているかをチェックしているプログラムがあったとしましょう。
strcmp(str, " ");
このプログラムを置き換えプログラムで変換した場合、(タブ表示してくれない)エディタでの見た目は同じになりますが、プログラム自体は「文字配列に空白4個が入っているかをチェック」が「文字配列にタブが入っているかをチェック」に変化してしまいますので同じ動作をするプログラムではなくなってしまいます。
strcmp(str, "\t");
つまり、コンパイル時に無視される関数の前や後ろの空白はタブに変換するが、コンパイルに影響する文字定数に含まれる含まれる空白は変換しないようにしなければならないということです。
Re:無題
Posted: 2009年5月27日(水) 10:51
by non
御津凪さんの言われていることは・・・
#include <stdio.h>
int main(void){
printf( " 1\n" );
printf( " 2\n" );
printf( " 3\n" );
printf( " 4\n" );
return 0;
}
をデータとして入力したとする。もちろんTABは使っていない。
これをバイナリエディタで確認すると・・
printf( " 3\n" );
は、元のデータでは
20 20 20 20 70 72 69 6E 74 66 28 20 22 20 20 20 20 20 20 33 5C 6E 22 20 29 3B 0D 0A
ですが、
あなたのプログラムの出力は
09 70 72 69 6E 74 66 28 09 22 09 20 20 20 33 5C 6E 22 09 29 3B 0D 0A
となります。
で、元のプログラムを実行するとこの行は(3の前にスペース6文字)
3
TABに置き換えられたプログラムを実行すると、(TAB=4で確認できるとしたら)
3
になって位置がずれます。(3の前にスペース7文字)
ですから" "や' 'で囲まれた部分はTABに変換しないようにしなければいけないということです。
Re:無題
Posted: 2009年5月27日(水) 10:53
by toyo
文字列の長さも変わりますね
#include <stdio.h>
#include <string.h>
int main(void)
{
char* space = " ";
if (strlen(space) == 8)
{
printf("Hello World");
}
else
{
printf("Error");
}
return 0;
}
これを変換すると実行結果が変わってしまいます
Re:無題
Posted: 2009年5月27日(水) 11:36
by 研修生
文字のサイズや長さってのは当たり前すぎる解答とか意味不明なこといわれたんで
nonさんの仰っているズレる理由をもう少し詳しくお聞きしたい。
それが御津凪さんが仰っている
プログラムで使う文字列・文字定数自体に
置き換え処理が行われる可能性があるからです。
ですか?
Re:無題
Posted: 2009年5月27日(水) 12:08
by non
何がわからないのかわからないので、どこをどう詳しく説明すればいいのかわからない。
>元のデータでは
>20 20 20 20 70 72 69 6E 74 66 28 20 22 20 20 20 20 20 20 33 5C 6E 22 20 29 3B 0D 0A
>ですが、
>あなたのプログラムの出力は
>09 70 72 69 6E 74 66 28 09 22 09 20 20 20 33 5C 6E 22 09 29 3B 0D 0A
>となります。
この部分は理解できますか?
Re:無題
Posted: 2009年5月27日(水) 13:01
by 研修生
バイナリエディタに関しては無知識なのでかなり曖昧ですが・・
元ソースと変換後のソースが要は別物ってのはわかりました。
それはそのバイナリエディタ?ですか、それを見ればわかるのでしょう。しかし
私が教えていただきたいのは結果ではなくて原因の方です。
何故そのようなズレが起こるのか、がさっぱりでして。
Re:無題
Posted: 2009年5月27日(水) 13:17
by Mist
原因?
タブというのは必ず同じ幅になるわけではない。
この辺を勘違いしていませんか?
タブは桁をそろえるためのものであり、タブ幅が4の環境ではタブの次が文字が4の倍数+1の位置にくるようにそろえるために適切な幅に変換されます。
abc (空白4個の後ろに3文字)
を変換した場合は、空白4個とタブ1個は同等ですので同じ表示になりますが
abc abc (3文字の後ろに空白4個の後ろに3文字)
というような場合、空白4個をタブ1個に変換するとタブは後ろのaを5文字目にくるようにするために1文字の幅だけになってしまいます。
「abc\tabc」は「abc abc」にしかなりません。
ですので、「空白が4個連続した→タブ一個に変換」という設計がそもそも間違っています。
Re:無題
Posted: 2009年5月27日(水) 14:32
by 研修生
#include
int main(int argc, char* argv[/url])
{
printf("%c\n", ' ');
printf( " A\n");
return 1;
}
これをやるとどうなりますか?
下の方は元ソースだと4つめの所にAがあります
変換後ソースだと9つめの所にAがあります。コンパイラのタブストップとVisualStudioのタブストップが違うので
ですが少し混乱してきたので説明してもらえませんか
Re:無題
Posted: 2009年5月27日(水) 14:59
by 研修生
下の方はズレてますね。上の方もか
Re:無題
Posted: 2009年5月27日(水) 15:02
by Mist
VisualStudioのタブ幅が8に設定されているのじゃないですか?
タブ幅はそれを表示する実行環境の設定に依存します。
プログラム側でこれを操作することはできません。
つまり、空白4個を1個のタブに変換した場合、変換後のソースをタブ幅が8に設定されている環境で見れば必ずずれます。
VSのタブ設定を変更すれば同じに見えるでしょう。
というか、タブ幅の設定よる見え方のずれは「文字列や文字定数を特別処理しないとソースコードとしては同じものにならないとか言われた」とは何の関係もないですけど、こっちはもういいのでしょうか?
Re:無題
Posted: 2009年5月27日(水) 15:18
by 研修生
ズレて文字列や文字定数の値がかわっていしまってると思ったのですが違うのですか?
対処はそこだけ変換しないようにすればいいだけだから気にしなくて構いませんが、
どこが違ってるのかわからないと質問したらさきほど示したソースを
変換前と変換後のソースで実行してみなさいと言われたのでタブ幅の設定による見え方のずれ
以外にもどこかしら違う所があるはずですが。
Re:無題
Posted: 2009年5月27日(水) 15:25
by Mist
> ズレて文字列や文字定数の値がかわっていしまってると思ったのですが違うのですか?
違います。
他の人も指摘していますが、研修生さんが作られたプログラムでは変換してはいけない空白まで変換してしまっています。
これは設定の違いによる見え方以前の問題です。
どう直すべきかはnonさんが答えておられますが・・・
> ですから" "や' 'で囲まれた部分はTABに変換しないようにしなければいけないということです。
Re:無題
Posted: 2009年5月27日(水) 16:27
by 研修生
その変換してはいけない理由は文字定数内の値がかわるからですよね?
他にもあるのかな
Re:無題
Posted: 2009年5月27日(水) 21:04
by たいちう
研修生さんはそのハンドルネームや質問の内容・時期から、
研修中の新入社員なのでしょうか。
掲示板に質問を繰り返すよりも教官役の人に聞いたほうが効率が良いのでは?
もしもリアルに質問するのが苦手だとすると、
これは絶対治さないといけないことですよ。
そうだとしても何か事情があるのかもしれないし、あくまでも一般論です。
自分が該当しないならば気を悪くしないでくださいね。
いずれにしても掲示板は質問を歓迎しています。