無題

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
研修生

無題

#1

投稿記事 by 研修生 » 16年前

空白の列を同じスペーシングを行なう最少の数のタブおよびブランクで置き換えるプログラム
を作成していまして、下記のように完成しました。
#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:無題

#2

投稿記事 by 御津凪 » 16年前

文字列・文字定数の中にも空白がある場合、そこを置き換えられてしまったらコードは違うものになります。

研修生

Re:無題

#3

投稿記事 by 研修生 » 16年前

それはどうしてです? その理由が知りたいのです。

御津凪

Re:無題

#4

投稿記事 by 御津凪 » 16年前

int main(){
    printf( "  1\n" );
    printf( "    2\n" );
    printf( "      3\n" );
    printf( "        4\n" );
    return 0;
}
というようなソース上でインデント整形済みの文字列があるコードがあったとします。
(文字列の空白は半角スペース)
これを研修生さんのコードで適用すると、適用後のコンパイル・実行結果は、
崩れた形で出力されてしまいます。
(適用元のタブの長さが4で指定されていて、出力先が4以外の場合、さらにずれます)

また、
putchar ( ' ' );
と、半角含みのコードなどの原因で ' ' がタブ文字に置き換えられてしまったら
半角スペースの出力ではなく、タブ文字の出力になってしまいます。

条件式でこのような影響のある置き換えが起これば、
もちろん正しい(同じ)プログラムコードではなくなります。

研修生

Re:無題

#5

投稿記事 by 研修生 » 16年前

int main(){
    printf( "  1\n" );
    printf( "    2\n" );
    printf( "      3\n" );
    printf( "        4\n" );
    return 0;
}
を適用してもまるで同じになります。
おそらくファイル内のタブを空白に変換してないのでは?
このプログラムではタブが認識できないので・・
変換せずに適用するとインデントが崩れます。

御津凪

Re:無題

#6

投稿記事 by 御津凪 » 16年前

上に書いたことは
"変換を適用したソースコードをコンパイルして実行した時のコンソールの出力"
についてです。

変換の適用前と適用後のソースコードを実行して比べてみましたか?

研修生

Re:無題

#7

投稿記事 by 研修生 » 16年前

うーんわからないですね。実行してみましたが確かにずれますがインデントがずれるのはやはりタブ関係が原因にしか見えない。文字定数と文字列が問題とのことですから・・

御津凪

Re:無題

#8

投稿記事 by 御津凪 » 16年前

> 文字定数と文字列が問題とのことですから・・

これは、

> 実行してみましたが確かにずれますが…

ということです。

ただし、変換時にタブを考慮していないのが原因ではなく、プログラムで使う文字列・文字定数自体に
置き換え処理が行われる可能性があるからです。
"    "
↑は空白4文字(+終端文字)の5バイトの文字列を示していますが、
この空白4文字がタブ文字に置き換えられてしまったら、
タブ1文字の(+終端文字)の2バイトの文字列に変わってしまいます。

よって、文字列・文字定数の中身の文字は変換しないように特別処理しないといけないという意味です。


もしこれでもわからなかったら、
(こちらからは散々似た様な回答をしているので)

> 文字列や文字定数を特別処理しないとソースコードとしては同じものにならない

といわれた方にもう少し詳しい意味(ソースコードとしては同じものにならないのはなぜか)を聞いてください。
というより聞いたほうが早かったかもしれませんが…

Mist

Re:無題

#9

投稿記事 by Mist » 16年前

こういう例だとわかるでしょうか。
strcmpでstrという文字配列に空白4個が入っているかをチェックしているプログラムがあったとしましょう。
strcmp(str, "    ");
このプログラムを置き換えプログラムで変換した場合、(タブ表示してくれない)エディタでの見た目は同じになりますが、プログラム自体は「文字配列に空白4個が入っているかをチェック」が「文字配列にタブが入っているかをチェック」に変化してしまいますので同じ動作をするプログラムではなくなってしまいます。
strcmp(str, "\t");
つまり、コンパイル時に無視される関数の前や後ろの空白はタブに変換するが、コンパイルに影響する文字定数に含まれる含まれる空白は変換しないようにしなければならないということです。

non

Re:無題

#10

投稿記事 by non » 16年前

御津凪さんの言われていることは・・・
#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に変換しないようにしなければいけないということです。

toyo

Re:無題

#11

投稿記事 by toyo » 16年前

文字列の長さも変わりますね
#include <stdio.h>
#include <string.h>

int main(void)
{
    char* space = "        ";
    if (strlen(space) == 8)
    {
        printf("Hello World");
    }
    else
    {
        printf("Error");
    }
    return 0;
}
これを変換すると実行結果が変わってしまいます

研修生

Re:無題

#12

投稿記事 by 研修生 » 16年前

文字のサイズや長さってのは当たり前すぎる解答とか意味不明なこといわれたんで
nonさんの仰っているズレる理由をもう少し詳しくお聞きしたい。
それが御津凪さんが仰っている
プログラムで使う文字列・文字定数自体に
置き換え処理が行われる可能性があるからです。

ですか?

non

Re:無題

#13

投稿記事 by non » 16年前

何がわからないのかわからないので、どこをどう詳しく説明すればいいのかわからない。
>元のデータでは
>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:無題

#14

投稿記事 by 研修生 » 16年前

バイナリエディタに関しては無知識なのでかなり曖昧ですが・・
元ソースと変換後のソースが要は別物ってのはわかりました。
それはそのバイナリエディタ?ですか、それを見ればわかるのでしょう。しかし
私が教えていただきたいのは結果ではなくて原因の方です。
何故そのようなズレが起こるのか、がさっぱりでして。

Mist

Re:無題

#15

投稿記事 by Mist » 16年前

原因?
タブというのは必ず同じ幅になるわけではない。
この辺を勘違いしていませんか?

タブは桁をそろえるためのものであり、タブ幅が4の環境ではタブの次が文字が4の倍数+1の位置にくるようにそろえるために適切な幅に変換されます。
abc (空白4個の後ろに3文字)
を変換した場合は、空白4個とタブ1個は同等ですので同じ表示になりますが
abc    abc (3文字の後ろに空白4個の後ろに3文字)
というような場合、空白4個をタブ1個に変換するとタブは後ろのaを5文字目にくるようにするために1文字の幅だけになってしまいます。
「abc\tabc」は「abc abc」にしかなりません。

ですので、「空白が4個連続した→タブ一個に変換」という設計がそもそも間違っています。

研修生

Re:無題

#16

投稿記事 by 研修生 » 16年前

#include
int main(int argc, char* argv[/url])
{
    printf("%c\n",    ' ');
    printf( "   A\n");

    return 1;
}
これをやるとどうなりますか?
下の方は元ソースだと4つめの所にAがあります
変換後ソースだと9つめの所にAがあります。コンパイラのタブストップとVisualStudioのタブストップが違うので
ですが少し混乱してきたので説明してもらえませんか

研修生

Re:無題

#17

投稿記事 by 研修生 » 16年前

下の方はズレてますね。上の方もか

Mist

Re:無題

#18

投稿記事 by Mist » 16年前

VisualStudioのタブ幅が8に設定されているのじゃないですか?

タブ幅はそれを表示する実行環境の設定に依存します。
プログラム側でこれを操作することはできません。

つまり、空白4個を1個のタブに変換した場合、変換後のソースをタブ幅が8に設定されている環境で見れば必ずずれます。
VSのタブ設定を変更すれば同じに見えるでしょう。

というか、タブ幅の設定よる見え方のずれは「文字列や文字定数を特別処理しないとソースコードとしては同じものにならないとか言われた」とは何の関係もないですけど、こっちはもういいのでしょうか?

研修生

Re:無題

#19

投稿記事 by 研修生 » 16年前

ズレて文字列や文字定数の値がかわっていしまってると思ったのですが違うのですか?
対処はそこだけ変換しないようにすればいいだけだから気にしなくて構いませんが、
どこが違ってるのかわからないと質問したらさきほど示したソースを
変換前と変換後のソースで実行してみなさいと言われたのでタブ幅の設定による見え方のずれ
以外にもどこかしら違う所があるはずですが。

Mist

Re:無題

#20

投稿記事 by Mist » 16年前

> ズレて文字列や文字定数の値がかわっていしまってると思ったのですが違うのですか?
違います。
他の人も指摘していますが、研修生さんが作られたプログラムでは変換してはいけない空白まで変換してしまっています。
これは設定の違いによる見え方以前の問題です。

どう直すべきかはnonさんが答えておられますが・・・
> ですから" "や' 'で囲まれた部分はTABに変換しないようにしなければいけないということです。

研修生

Re:無題

#21

投稿記事 by 研修生 » 16年前

その変換してはいけない理由は文字定数内の値がかわるからですよね?
他にもあるのかな

たいちう

Re:無題

#22

投稿記事 by たいちう » 16年前

研修生さんはそのハンドルネームや質問の内容・時期から、
研修中の新入社員なのでしょうか。

掲示板に質問を繰り返すよりも教官役の人に聞いたほうが効率が良いのでは?
もしもリアルに質問するのが苦手だとすると、
これは絶対治さないといけないことですよ。
そうだとしても何か事情があるのかもしれないし、あくまでも一般論です。
自分が該当しないならば気を悪くしないでくださいね。

いずれにしても掲示板は質問を歓迎しています。

閉鎖

“C言語何でも質問掲示板” へ戻る