超初級C言語

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

超初級C言語

#1

投稿記事 by はげ » 15年前

int main(void)
{
    if(isdigit('11') == 1){
        printf("数字");
    }
    else{
        printf("数字ではない");
    }
        
    return 0;
}

int isdigit(char ch)
{
    if(ch >= '0' && ch <= '9'){
        return 1;
    }
    else{
        return 0;
    }
}
このプログラムでcharがintになってるのですがこのプログラムはおかしいでしょうか?
軽くテストしてみましたが求める結果にはなります。

sizuma

Re:超初級C言語

#2

投稿記事 by sizuma » 15年前

本当に求めたい結果になりますか?

ところで、どこでcharからintになってると思っているのでしょうか?

DVDM

Re:超初級C言語

#3

投稿記事 by DVDM » 15年前

>>はげさん
[color=gray>>軽くテストしてみましたが求める結果にはなります。[/color]
どのような結果を望んているかが解らないため、
求めている結果になったのなら合っているのではないでしょうか?

正直、求めている結果になっていない気がしますけども。

はげ

Re:超初級C言語

#4

投稿記事 by はげ » 15年前

拙い知識で申し訳ないのですが'11'の所でintからcharに(逆でした)切り詰められます。
定数値が切り捨てられましたと警告が2つでます。

ちょっと頭をひねってみたのですがcharは1バイトです。'1'や'2'などの場合警告は出ません。
おそらく型の理解ができていないのだと思いますが・・
'11'は1バイトではないのでint型になりこの関数を使うと切り詰められるという話でしょうか?

求めたい結果はisdigitと同じなので数字かどうかの判断です。この場合は11が数字かどうかとか
aaが数字かどうかとか1aが数字かどうかとかそんな感じです

box

Re:超初級C言語

#5

投稿記事 by box » 15年前

数字かどうかを判断するのは1バイトずつにしてください。

hello world

Re:超初級C言語

#6

投稿記事 by hello world » 15年前

多文字リテラル('11')が int 型だからでしょう。
設定される値は処理系依存となります。


取り得る値をちゃんと理解しているならよいのですが、
文字リテラルは1文字づつのほうが無難だと思います。

文字列が使いたかったのかな?とも推測しますが・・・。

sizuma

Re:超初級C言語

#7

投稿記事 by sizuma » 15年前

>ちょっと頭をひねってみたのですがcharは1バイトです。'1'や'2'などの場合警告は出ません
''は文字を囲む時に使います。'11'は文字列なので
char [/url]str = "11";
保持するならこうですね。

>得られる値は処理系依存
そうなんですか。'文字列'とするなんて発想はなかったので、知らなかったです。
処理系依存のプログラムは出来るだけ避けた方がいいと僕は思います。
僕の環境だと、こうなりますね。

#include<stdio.h>

int isdigit(char ch);

int main(void){
int intval = '11';
int intval2 = '1';
printf("'a1' = 0x%x\n'1' = 0x%x\n",intval,intval2);
printf("(char)intval = %c\n(char)intval2 = %c",intval,intval2);
return 0;
}

>'11' = 0x3131
>'1' = 0x31
>(char)intval = 1
>(char)intval2 = 1


#mainのreturn忘れてたので編集--; 画像

はげ

Re:超初級C言語

#8

投稿記事 by はげ » 15年前

なんとなくわかりました。
1バイトずつならこの関数だけでいけます
1111とか111aとかを判断したいのなら
char str[100] = "55544";
int len = strlen(str);
for(int i=0; i < len; i++){
    if(isdigit(str) ==0){
             printf("数字以外の文字がある");
              return 0;
    }
}
    
printf("数字");
    
        
return 0;


こんな感じにすれば大丈夫かな
ありがとうございました。 画像

softya

Re:超初級C言語

#9

投稿記事 by softya » 15年前

C言語の場合、文字リテラルはint型ですね。
sizumaさんも試しておられる通り、'11'とするとちゃんと2バイト分の文字データが入っています。
ただ、処理系依存ですがchar型が1バイトの場合は、int型から切り捨てられます。
今回の質問者さんの場合は、'11'という文字定数ですので2バイトになるのが代入前には分かっているわけで、これをコンパイラがチェックしてくれてエラーを出してくれています。1バイトの定数ならエラーになりません。

で、C言語で文字列の処理を作る場合は、4文字までしか格納出来ないint型を使うのは面倒なので普通文字列型配列を使います。

補足事項も含めてまとめると
・char型が1バイトなのは処理系依存。
・文字が1バイトかどうかも処理系依存。
・int型が4バイトかどうかも処理系依存。
・不定長の文字の並びは、文字列として扱うのが効率的。
・文字列は、char型の配列で終端が'\0'
・代入時に切り捨てられる恐れがある場合、コンパイラによっては警告が出る。

たかぎ

Re:超初級C言語

#10

投稿記事 by たかぎ » 15年前

isdigitと同じ意味の関数を作るのであれば...
#include <assert.h>
#include <limits.h>
#include <stdio.h>

int isdigit(int c)
{
  assert(0 <= c && c <= UCHAR_MAX || c == EOF);
  if ('0' <= c && c <= '9' && c != EOF)
    return 1;
  return 0;
}
ということになります。
引数の型はcharではなくintなので注意してください。
http://www.kijineko.co.jp/tech/supersti ... -char.html

ちなみに...

> ・char型が1バイトなのは処理系依存。

charは常に1バイトです。

> ・文字が1バイトかどうかも処理系依存。

多バイト文字やワイド文字を除けば、文字は1バイトです。

hello world

Re:超初級C言語

#11

投稿記事 by hello world » 15年前

をぉなるほど。内容が変わるもんんだと、
勘違いで覚えてました。
型の話ですよねぇw

softyaさん、たかぎさん。詳細なご説明まで
ありがとうございました

sizuma

Re:超初級C言語

#12

投稿記事 by sizuma » 15年前

>charは常に1バイトです。
sizeof(char)が1なのが定義されてるだけだと思ってました。

ということは、char型が9ビットの環境では、1バイト自体が9ビットの環境ってことなんでしょうか?

sizuma

Re:超初級C言語

#13

投稿記事 by sizuma » 15年前

>ということは、char型が9ビットの環境では、1バイト自体が9ビットの環境ってことなんでしょうか?
きじねこ様で見てみたら、そういうことみたいですね。

勝手にリンクを貼らせていただきます。
http://www.kijineko.co.jp/tech/supersti ... -bits.html

違う環境を体験しないと、すぐ忘れそうです・・・

box

Re:超初級C言語

#14

投稿記事 by box » 15年前

> >charは常に1バイトです。
> sizeof(char)が1なのが定義されてるだけだと思ってました。

charが常に1バイトであることを知らなくて、
sizeof(char)が1であることを定義していることは知っている、
という状況が理解できません。

たかぎ

Re:超初級C言語

#15

投稿記事 by たかぎ » 15年前

> ということは、char型が9ビットの環境では、1バイト自体が9ビットの環境ってことなんでしょうか?

そうです。
http://www.kijineko.co.jp/tech/supersti ... -bits.html

添付画像はJIS X3010:2003からの引用です。
sizeof演算子の結果がオペランドのバイト数であり、sizeof(char)が1ですので、charのサイズは必ず1バイトになります。

たかぎ

Re:超初級C言語

#16

投稿記事 by たかぎ » 15年前

> 違う環境を体験しないと、すぐ忘れそうです・・・

移植性に関しては、規格上がどうであるかは調べればすぐに分かるのですが、現実的な落とし所をどうするかは難しいところです。
C/C++迷信集ではそこまで突っ込んでいませんので、その手の話題は出版物で扱えればと考えています。
# ウェブ上のコンテンツと棲み分けが必要ですので。

今回の件に関しては、charが16ビットや32ビットなどの処理系は実際に存在するので、規格上の話と割り切ることはできません。
Windows(というかIntel互換の環境)しか扱わないのであれば気にすることはありませんが、DSPなどを使い始めると、そういった状況に遭遇します。

たいちう

Re:超初級C言語

#17

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

> charが常に1バイトであることを知らなくて、
> sizeof(char)が1であることを定義していることは知っている、
> という状況が理解できません。

32ビットのchar型に対してsizeof(char)が1を返すとき、
このchar型が1バイトだと考えるのには私にも抵抗があります。
幸か不幸か私は経験が無いですが。

「sizeofはサイズを返すはずだよな、でも、
この1を1バイトと考えても良いのかな?」

という状況ではないでしょうか。

sizuma

Re:超初級C言語

#18

投稿記事 by sizuma » 15年前

>Windows(というかIntel互換の環境)しか扱わないのであれば気にすることはありませんが、DSPなどを使い始めると、そういった状況に遭遇します。
携帯電話のソフトウェア開発をしてる会社を受ける予定もあるし、組込みの仕事だといろいろな環境があると思うので、処理系依存な言語使用はなるべく注意しておきたいと思ってます。

>Jis
規格はやっぱり読み難いです。
sizeof演算子を評価するのは可変長配列をオペランドにしたときだけなんですね。それ以外は評価しないということはマクロで整数に置き換えるのとほぼ同じということでしょうか。
プリプロセスみたいにコンパイル前に置き換わることはないと思うんですけど・・・・



>boxさん
>charが常に1バイトであることを知らなくて、
>sizeof(char)が1であることを定義していることは知っている、
>という状況が理解できません。
確かに全バイトのビットが変わらないとポインタ演算なんてごっちゃごちゃになりますね。
実はsizeof演算子を使ったことがない、って理由もあります。
charが8ビットより大きい環境だと、charだけが8ビットよりおおきいのかな?と思ってました。

例えばこんなイメージです
sizeof(char) = 9bit(1バイトより大きいけど、sizeofでは1が絶対返される)
sizeof(char[2])=18bit(2)
sizeof(int) = 32bit(4)
sizeof(int [2])=64bit(8)
たいちうさんの言ってるようなこと、といいたいですけど、ただchar型について勘違いしてたみたいですね。

C言語っていろんな処理系を想定してて、その処理系の最適な1バイトのビット数が違ったりするから、最低限表現できる範囲だけを決めている、ということでしょうか。
Javaみたいにきちっと決めてあると覚えるのは楽なんですけどね。 画像

たかぎ

Re:超初級C言語

#19

投稿記事 by たかぎ » 15年前

> sizeof演算子を評価するのは可変長配列をオペランドにしたときだけなんですね。それ以外は評価しないということはマクロで整数に置き換えるのとほぼ同じということでしょうか。

sizeofは常に評価されます。
そうではなく、sizeofのオペランドが評価されない場合があるのです。必要なのは型だけですからね。
可変長配列の場合は、評価しないと型がわからないので評価されます。

> プリプロセッサみたいにコンパイル前に置き換わることはないと思うんですけど・・・・

可変長配列以外の場合は整数定数式になりますので、コンパイル時に解決されます。

sizuma

Re:超初級C言語

#20

投稿記事 by sizuma » 15年前

>sizeofは常に評価されます。
>そうではなく、sizeofのオペランドが評価されない場合があるのです。必要なのは型だけですからね。
なるほど。つまり

sizeof(char);//sizeofを評価するわけで、オペランドとして与えられてるcharが評価されるわけではない

char buf[n];
sizeof(buf);//オペランドであるbufを評価しないと、配列のサイズが分からない

ということですよね。

>可変長配列以外の場合は整数定数式になりますので、コンパイル時に解決されます
なるほど、、、こういうのを確認するときに、はきだされるアセンブリコードを読めるといいんですけどね。
CASLならある程度読めるんですけど(笑




#僕が上の記事を編集したので、プリプロセス→プリプロセッサ、になってしまいました。
#後で読んで、なんか訂正したいな、と思うことがあるので・・・誤字も多いですし。
#訂正するなら、プレビューで確認してから投稿しないとダメですね。失礼しました。

softya

Re:超初級C言語

#21

投稿記事 by softya » 15年前

私も汎用機(富士通)からゲーム機、パソコン、一部のワンチップマイコンなどの開発経験してますが、1バイト=8ビットの環境以外を使ったことが無いですね。
なのでC言語の移植要件もINTEL系CPUを使ったWindowsとLinuxで動くこととか、PowerPCとINTELの両方で動くこととか程度の経験しかないです。

たかぎ

Re:超初級C言語

#22

投稿記事 by たかぎ » 15年前

> なるほど、、、こういうのを確認するときに、はきだされるアセンブリコードを読めるといいんですけどね。

それは間違いありません。
不幸なのは、IA32のアセンブリコードは非常に読みにくく、アセンブリ言語に不慣れな人は大抵挫折します。
最初は、H8とかMIPSとかV850とか、そのあたりから入った方が結局は近道です。
ARMやSHも最初は読みにくいので、避けた方がよいかもしれません。

今、↓の続編を考えています。いつになるか分かりませんが、参考になるようにしたいですね。
http://www.kijineko.co.jp/node/649

たかぎ

Re:超初級C言語

#23

投稿記事 by たかぎ » 15年前

連続投稿が多くてすみません。

> CASLならある程度読めるんですけど(笑

CASL用のCコンパイラを作るとしたらどうします?
sizeof(char) = sizeof(short) = sizeof(long) = 1 かつ CHAR_BIT = 16 にするのが一番簡単で効率もよいですね。

これを強引に1バイト = 8ビットにしようとすると、charでメモリアクセスするには、1ワードを上位下位に分割しなければならなくなります。
結果的に、char*とvoid*はint*等より少なくとも1ビット多くの情報が必要になるため、sizeof(char*) = sizeof(void*) = 2 かつ sizeof(int*) = 1 になるのではないでしょうか?

私の場合は、TOPPERSプロジェクト(http://www.toppers.jp/が16ビットのものも含まれています。
汎整数拡張されない処理系とか、constの有無でポインタサイズが変わる処理系とか、構造体のメンバの配置順が記述順にならない処理系とか、sizeof(float) = sizeof(double) = 4(32ビット)の処理系とか、long longが32ビットの処理系とか、いろいろな非標準処理系も検討してきたわけです。

sizuma

Re:超初級C言語

#24

投稿記事 by sizuma » 15年前

うむむ、、、
つまりその処理系がリアルタイム性(処理速度)が求められる場合は、1バイトを8ビットとしてコンパイルするとなんかいろいろ面倒ってことでしょうか。

sizeof(char)が1バイトを表すんで、CHAR_BIT=16とした場合に強引に1バイト=8ビットにしようとすることはないのでしょうけど
>sizeof(char*) = sizeof(void*) = 2 かつ sizeof(int*) = 1
うわーごちゃごちゃしてわけがわからなくなってきた・・・
char*はなぜint*より1ビット多く必要なのでしょうか?
とりあえず、リンク先を読んで勉強してきます!

たかぎ

Re:超初級C言語

#25

投稿記事 by たかぎ » 15年前

> つまりその処理系がリアルタイム性(処理速度)が求められる場合は、1バイトを8ビットとしてコンパイルするとなんかいろいろ面倒ってことでしょうか。

リアルタイム性というのは、処理速度が速いかどうかではなく、処理にかかる時間が予想できるということです。
今回の件については、速度やサイズなどの効率を上げるには、CASL(というかCOMMET)のCコンパイラは1バイトが16ビットでなければなりません。

COMMETは、16ビットワードを単位としてアドレスが割り振られています。アドレスは16ビットです。
これを強引に1バイト=8ビットとして処理系を実装する場合...

データは16ビット単位でしか読み書き出きませんから、8ビットごとのアドレスを割り振るには、COMMETのアドレスにもう1ビット追加しなければなりません。
つまり、char*やvoid*は17ビットが必要になります。これに対して、shortやintなどは16ビットで済みます。

> sizeof(char*) = sizeof(void*) = 2 かつ sizeof(int*) = 1 になるのではないでしょうか?

これは私にも混乱がありました。
1バイト=8ビットにしようというのですから、sizeof(char*) = sizeof(void*) = 4バイト = 32ビットであり、sizeof(short*) = sizeof(int*) = 2バイト = 16ビットですね。
char*を24ビット(うち7ビットが詰め物ビット)にすることもできますが、それでは非常に効率が悪くなります。

閉鎖

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