たとえば以下のようなif文で、A B C が評価される順番は
言語の規約上、明確になっているのでしょうか?

if ( A && B && C ) { }

また例えば A, B, C の順番に評価されるとして、B が
FALSE の場合は C を評価する必要はありませんが、
この場合、Cは評価されないことは言語規約上、明確に
なっているのでしょうか?

手元のコンパイラで試した結果では
評価順は A -> B -> C
で B で FALSE を返すようにしたら C は実行されませんでした。
ただ、これが実装依存か、言語の標準仕様かという点が
気になっています。

このQ&Aに関連する最新のQ&A

A 回答 (7件)

「A,B,Cの順に評価され、AがFALSEならB,Cは評価されず、AがTRUEでBがFALSEならCは評価されない」が標準仕様です。



論理AND演算子、論理OR演算子は左から右に評価され、第1オペランドだけで値が決定すると、第2オペランドの評価は行われません。

http://www.microsoft.com/japan/developer/library …
http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide2 …
http://www.st.rim.or.jp/~phinloda/cqa/cqa10.html …
    • good
    • 0

> 逆にこれら以外は(最適化とは無関係に)不定となっています.


","演算子も左から評価されると規定されています。
ただし同じ","でも、関数の引数の評価順序は規定されていませんのでご注意を。たとえば、
f( g(x), (t=2, t+3), h(x) );
で、第2引数は必ず5になりますが、
gとhのどちらが先に呼び出されるかはわかりません。
    • good
    • 0
この回答へのお礼

多くの回答ありがとうございました。
大変参考になりました。

お礼日時:2005/04/12 19:25

オペランドの評価順序が決まっている演算子は


&&, || (第1オペランド→第2オペランドの順で, 第1オペランドで値が決まるなら第2オペランドは評価しない) と
?: (第1オペランド→第2オペランドまたは第3オペランドの順)
だけで, 逆にこれら以外は(最適化とは無関係に)不定となっています.
    • good
    • 0

ちょっと気になったので投稿させていただきます。



> 順序をかえる場合があります。
確かに、意味が変わらない範囲内で「内部的には」実は評価の順序が変わっている、というのは今回の件に限らず最適化では普通にあることですが、
今回の話は、No.1~No.3の方の答えられたような順序で評価をしているように「外部からは」見えるという話であって、最適化による評価順序の変更とは切り分けたほうがよいように思います。
    • good
    • 0

みなさんは、a,b,cの順に評価するとかかれていますが


実は、昔、古いコンパイラ等では、強力な最適化を
実現するために、同じ結果になることが確定された
場合、順序をかえる場合があります。

例えば・・・・Z80 (16bitレジスタが3つ)を例にします。
 unsigned a,b,c; /* unsigned int */
 a=23513;
 if(a > 20000) {
  b=15325;
  if(b>10000) {
   c=31252;
   if (a && b && c) {
のような場合、実はレジスタ上に残っている数字は
b と c と 比較用の 10000 だけになります。
そうすると、最適化する上で、最初に b と c を
最初に比較することで、メモリからの読み出しの分
最適化することができます。
    • good
    • 0

#1の方が回答されている通り、「A,B,Cの順に評価され、Aが偽ならB,Cは評価されず、Aが真でBが偽ならCは評価されない」のが標準仕様です。



通常、演算子のオペランドの評価順序は(演算子の優先順位とは関係なく)不定ですが、&&や||演算子等は例外的に評価順序が決められています。
厳密に言えば、||や&&演算では、第一オペランドの評価の直後が副作用完了点となっています。以後、詳しく調べたい場合は「副作用完了点」で調べてみてください。

なお、C++で&&や||演算子を多重定義した場合には、こうした動作にはなりませんので要注意です。
    • good
    • 0

>たとえば以下のようなif文で、A B C が評価される順番は


>言語の規約上、明確になっているのでしょうか?

はい。「==」、「&&」などは演算子と呼ばれ、
優先順位が決められています。
慣れてくれば演算子の優先順位もある程度わかって
きますが、全部覚える必要はないでしょう。
()で優先順位を明確にするのも一つの手です。

http://www.bohyoh.com/CandCPP/C/operator.html
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q[C言語]コンソールからのデータ入力時の誤動作の回避方法

趣味でプログラミングをしております。
環境は、以下です。
Windows10
Mingw-w64
gcc version 5.2.0 (Rev4, Built by MSYS2 project)

https://oshiete.goo.ne.jp/qa/9287118.htmlの回答2にて、
3つの数字を入力し、数字でない場合は再入力を促すプログラムを提示しました。
これについて、他の回答者様より「fflush(stdin); は一般にはやっていけない操作」との回答をいただきました。

私の環境では、fflush(stdin)を使用しないと以下の様に1回目に誤ったデータを入力すると、再入力時のメッセージが2回繰り返し表示されます。
(推測ですが、windowsで改行コードが2Byteであることから発生しているのではと考えています)

fflush(stdin)を使用しないで、この問題を回避する適切な方法がありましたらご教示ください。

よろしくお願いします。


----------実行結果(fflush(stdin)を使用しない場合)
$ ./a.exe
重複しない3つの数字:abc
重複しない3つの数字:重複しない3つの数字:abc
重複しない3つの数字:重複しない3つの数字:
----------


----------ソース
#include <ctype.h>

#define BUF_SIZE 3 // 3文字

int main(void){
char buf[BUF_SIZE + 1];
int user;

while(1){
fflush(stdin);
printf("重複しない3つの数字:");
fflush(stdout);

fgets(buf, BUF_SIZE + 1, stdin);
if(!isdigit(buf[0])) continue; // 1文字目が数字かチェック
if(!isdigit(buf[1])) continue; // 2文字目が数字かチェック
if(!isdigit(buf[2])) continue; // 3文字目が数字かチェック
break;
}
user = atoi(buf);
printf("number : %d", user);

return 0;
}
----------

趣味でプログラミングをしております。
環境は、以下です。
Windows10
Mingw-w64
gcc version 5.2.0 (Rev4, Built by MSYS2 project)

https://oshiete.goo.ne.jp/qa/9287118.htmlの回答2にて、
3つの数字を入力し、数字でない場合は再入力を促すプログラムを提示しました。
これについて、他の回答者様より「fflush(stdin); は一般にはやっていけない操作」との回答をいただきました。

私の環境では、fflush(stdin)を使用しないと以下の様に1回目に誤ったデータを入力すると、再入力時のメッセージが2...続きを読む

Aベストアンサー

>他の回答者様より「fflush(stdin); は一般にはやっていけない操作」との回答をいただきました。

規格にstdinに対して実施した場合の動作が明記されていないから。
だったかと。
実装依存する。ということです。


>推測ですが、windowsで改行コードが2Byteであることから発生しているのではと考えています

ライブラリー依存でしょうかね。
¥rと¥nの両方をfgets()が改行として処理したのかも知れません。
gccだし。

>fflush(stdin)を使用しないで、この問題を回避する適切な方法がありましたらご教示ください。

読み込み用のバッファをもう少し大きく用意する。でしょうか。

1回目、"abc"を読み込みます。
第2引数で指定した3バイトに達したため。
stdinのバッファには¥rと¥nが残ってます。

2回目、¥rを読み込みます。
fgets()の仕様により改行コードに到達したため。

1回目の読み込みで残るのに注意です。
# 2回目で¥rだけなのか¥r¥nなのか、はたまた¥r¥nが¥nに変換されるのか…はfgets()の後で内容確認してください。

>他の回答者様より「fflush(stdin); は一般にはやっていけない操作」との回答をいただきました。

規格にstdinに対して実施した場合の動作が明記されていないから。
だったかと。
実装依存する。ということです。


>推測ですが、windowsで改行コードが2Byteであることから発生しているのではと考えています

ライブラリー依存でしょうかね。
¥rと¥nの両方をfgets()が改行として処理したのかも知れません。
gccだし。

>fflush(stdin)を使用しないで、この問題を回避する適切な方法がありましたらご教示ください。...続きを読む

Q2 ~ 200 の素数 a, b, c (a < b < c) が、b - a = c - b を満たすa,b,cをビット操作を用いて求め、すべてを表示せよ

ちょっと考えてみました。でも、分かりません・・・まず、int型のintvalに200bitを割り当てて、intval=0としたいのですが、どうしたらいいのでしょう??
とりあえず考えてみたプログラムを誰か見て下さい!!お願いします。
#define BYTESIZE 200
#define MAX 200
main()
{
int i,j,intval=0;
for(i=2;i<=MAX/2;i++)
{
if(intval&(1<<(i-1)){}
else for(j=i*2;j<=MAX;j+=i)intval|=(1<<(j-1));
}/*素数を0、それ以外を1に
for(i=2;i<=MAX/2;i++)
for(j=2;j<=(MAX-i)/2;j++)
if((intval&(1<<(i-1))&&(intval&(i+j-1))&&(intval&(1<<(i+2*j-1)))) print("%3d %3d %3d (%3d)\n",i,i+j,i+2*j,j);
}/*三つ子の素数を調べ出力

ちょっと考えてみました。でも、分かりません・・・まず、int型のintvalに200bitを割り当てて、intval=0としたいのですが、どうしたらいいのでしょう??
とりあえず考えてみたプログラムを誰か見て下さい!!お願いします。
#define BYTESIZE 200
#define MAX 200
main()
{
int i,j,intval=0;
for(i=2;i<=MAX/2;i++)
{
if(intval&(1<<(i-1)){}
else for(j=i*2;j<=MAX;j+=i)intval|=(1<<(j-1));
}/*素数を0、それ以外を1に
for(i=2;i<=MAX/2;i++)
for(j=2;j<=(MAX-i)/2;j++)
if((intval&...続きを読む

Aベストアンサー

まずint型は200ビットもありません。通常は32ビットです。
200ビット使いたければint型を7個用意する必要があります。
つまり
int intval[7];
宣言して、
intval[0] 0~31ビット
intval[1] 32~63ビット
intval[2] 64~95ビット
.
.
.
intval[6] 182~200ビット
として使います。

第iビットの情報を取り出すときは
(intval[i>>5]>>(i&31))&1

第iビットを1にするときは
intval[i>>5]|=1<<(i&31);

とすれば良いでしょう。
関数やマクロを用意することをお勧めします。
例えば
int get(int intval[],int i)
{
return (intval[i>>5]>>(i&31))&1;/*0か1が返って来る。*/
}

void on(int intval[],int i)
{
intval[i>>5]|=1<<(i&31);
}

という感じです。

まずint型は200ビットもありません。通常は32ビットです。
200ビット使いたければint型を7個用意する必要があります。
つまり
int intval[7];
宣言して、
intval[0] 0~31ビット
intval[1] 32~63ビット
intval[2] 64~95ビット
.
.
.
intval[6] 182~200ビット
として使います。

第iビットの情報を取り出すときは
(intval[i>>5]>>(i&31))&1

...続きを読む

QC言語Char型配列に小数値を入れる方法

C言語Char型配列に小数値を入れる方法について質問なんですが、
分からなく質問させていただきました。

(例)23.8を

float f = 23.8
char c[100];

cの配列の中に23.8を入れる

c[0] = '2'
c[1] = '3'
c[2] = '.'
c[4] = '8'
c[5] = '\0'


上記みたいに入ってほしいんですが、そういうC言語の関数ありますか?
itoaやsprintfを使わないでお願いします。

Aベストアンサー

> いえ、HEWで作成していて itoaとsprintfが使用できなくて質問しました

マイコンが何か、またツールチェインが何か知りませんが、いずれにせよsprintfが使えるはずです。
メモリが足りないということでしょうか?

必要な情報は小出しにせず、すべて明らかにしてください。

QC言語 配列で座標

C言語で二次元の配列a[11][11]を考えたとき、a[1][0]はxy座標の(1,0)を、a[0][5]はxy座標の(0, 5)を表しているという風な考えはあっているのでしょうか?
また、C言語で、xy座標で(0.5, 3.1)などの小数を表そうとしたらどうしたら良いのでしょうか?

Aベストアンサー

もう少し数の小さい例で説明します。
以下のように配列を宣言したとします。

***************
//配列宣言
int a[3][4];
***************

この場合 int型の値を格納できる変数が3×4=12個
作られたと考えることができます。

配列の使い方は以下のようになります。

*********************
//配列の扱い方の例
a[0][0]=1;
a[0][1]=234;
a[0][2]=-123;
a[0][3]=5;

a[1][0]=a[0][2];



*******************
つまり普通のint型の変数とそれぞれが同じ扱い方ができます。
どの様に使うかは様々です。

イメージとしては

  [0][1][2][3]
[0] □ □ □ □
[1] □ □ □ □
[2] □ □ □ □

このようなint型の値が格納できる箱が用意されるような感じです。

ここからは主観ですが
配列で座標を扱うといった概念はあまりないように思います。
たくさんの座標を扱うのであれば便利かもしれません。


少数の座標を表現する方法ですが

****************
//double型で座標を表現
double x = 0.5;
double y = 3.1;
****************

のように扱うといいかもしれません。
構造体を知っているのであれば
それで記述するとまとまって見やすいかもしれません。

もう少し数の小さい例で説明します。
以下のように配列を宣言したとします。

***************
//配列宣言
int a[3][4];
***************

この場合 int型の値を格納できる変数が3×4=12個
作られたと考えることができます。

配列の使い方は以下のようになります。

*********************
//配列の扱い方の例
a[0][0]=1;
a[0][1]=234;
a[0][2]=-123;
a[0][3]=5;

a[1][0]=a[0][2];



*******************
つまり普通のint型の変数とそれぞれが同じ扱い方ができます。
どの...続きを読む

Qc#について質問があります。 a b c d など任意の文字を入れたら abcd とスペースを

c#について質問があります。
a b c d
など任意の文字を入れたら
abcd
とスペースをなくすプログラムを作成したいです。
任意の数字なので
string a=console.ReadLine()
とします。
この後から分かりません。
わかる方教えてください(´・_・`)

Aベストアンサー

No1の方の回答は、
a内のスペースを""(長さ0の文字列)に置き換える方法です。
この方法がシンプルでかつ速いため、実戦では、この方法を採用したほうが良いでしょう。
a内のスペースを取り除くことを自前で行うには、どうするかという観点で考えると、
以下のようになります。
----------------------------------
using System;
namespace goo
{
class Program
{
static void Main(string[] args)
{
Console.Write("文字列を入力してください:");
string a = Console.ReadLine();
string b = "";
int i;
for (i = 0; i < a.Length; i++)
{
if (a[i] != ' ')
{
b = b + a[i];
}
}
Console.WriteLine(b);
}
}
}
------------------------------------------------------
結果を格納する文字列として、bを用意しておき、
a内の空白でない文字をbへ加算していきます。
実行結果は以下のようになります。
文字列を入力してください:a b c h
abch

No1の方の回答は、
a内のスペースを""(長さ0の文字列)に置き換える方法です。
この方法がシンプルでかつ速いため、実戦では、この方法を採用したほうが良いでしょう。
a内のスペースを取り除くことを自前で行うには、どうするかという観点で考えると、
以下のようになります。
----------------------------------
using System;
namespace goo
{
class Program
{
static void Main(string[] args)
{
Console.Write("文字列を入力してください:");
string a = Console.ReadLine()...続きを読む

QC言語 ポインタと配列

C言語で配列をあつかう場合、ポインタをつかうか、配列の添え字を使って処理するか迷うのですが、どちらが良いのでしょうか?
処理速度ではどちらが上でしょうか?

Aベストアンサー

いきなり
a[x]
と書いた場合は、他の回答のように
*(a+x)
と同じ処理速度です。

しかし
for(i=0;i<1000;) {
ホゲホゲ=a[i++];
}

型 *p = a;
for(i=0;i<1000;) {
ホゲホゲ=*p++;
}
では、処理速度に差が出ます。

前者では「毎回、aとiを加算して実効アドレス値を求め、値の取り出し後、iをインクリメントする」と言う処理が行われます。

しかし、後者では「毎回のアドレスの計算はせず、pから直接に実効アドレスをロードして使い、値の取り出し後、pに一定値を加算する」と言う処理が行われます。

「どちらが早いか?」は、コンパイラごと、実行するCPUごとに違うので、どちらと明言する事は出来ませんが、明らかに言えるのは「前者と後者では、異なる機械語コードが生成される筈だから、速度に差が出る筈」と言う事。

ま、どう考えても「毎回、加算を行ってアドレス値を作る」のと「アドレス値を持って来るだけ」なら、後者の方が早いでしょう(断言はしませんが)

そう言った訳で「連続したアドレスから順番に中身を取り出す」とか「連続したアドレスに順番に中身を詰め込む」なら、ポインタを用いるべきでしょう。

いきなり
a[x]
と書いた場合は、他の回答のように
*(a+x)
と同じ処理速度です。

しかし
for(i=0;i<1000;) {
ホゲホゲ=a[i++];
}

型 *p = a;
for(i=0;i<1000;) {
ホゲホゲ=*p++;
}
では、処理速度に差が出ます。

前者では「毎回、aとiを加算して実効アドレス値を求め、値の取り出し後、iをインクリメントする」と言う処理が行われます。

しかし、後者では「毎回のアドレスの計算はせず、pから直接に実効アドレスをロードして使い、値の取り出し後、pに一定値を加算する」と言う処理が行わ...続きを読む

QC言語でCLAMP(a,b,c)

と書けばこの値はどのような値になるでしょうか?

Aベストアンサー

CLAMPはgmacros.hで定義されているマクロです。
詳細はgmacros.hを見ればわかると思います。

QC言語 配列の長さの上限

C言語で配列Array[N]の長さNの上限っていくらなんでしょうか?
もし可能なのであれば上限を2147483647にしたいのですが、方法を教えてください。

Aベストアンサー

そもそもWindowsの32bit版はアプリが仮想メモリ空間を2GBしか使えません。2GBを超えるには64bit版が必要です。
たとえ64bit版OSだとしても添え字が2147483647って、単純なintの配列だとしても4x2147483647=8GB必要ですね。実メモリ16GBとかのPCを用意しますか?
そもそも配列で2147483647個必要なアルゴリズムに問題ありだと思います。

QC言語 a * b / c の計算

特に困っているわけではないのですが、エレガントな方法が見つからないので質問します。

a,c は32ビット、bは8ビット、0<a≦c、0<b がわかっているとします。
このとき、8ビットの整数計算値 a * b / c を「最大32ビットの範囲」で計算する方法、教えてください。
一応C言語で考えていますので、以下の***の部分の具体的な計算方法がわかればうれしいです。

int a,c; // 32bit 符号付き整数
signed char b,d; // 8bit 符号付き整数
if(a<2^(32-8)) d = a * b /c;
else **** ← この部分のプログラム

Aベストアンサー

決してエレガントではありませんが、a, cは正でありしかし符号付の型だという前提で a * b / c の整数の商を求めるのであれば、最初にa - cを求めて一時変数に代入しておき、bの数だけループし、ループ中に一時変数にaを加え、それがc以上になったらdを1加えて一時変数からcを引き去ることを繰り返せば、間違いなくすべての数値は32ビット以内に収まると思います。CPUにALUしかない時代の発想で、歳がばれますね・・・


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報