C言語なら俺に聞け 155

レス数が950を超えています。1000を超えると書き込みができなくなります。
1デフォルトの名無しさん (ワッチョイ 76ba-P5bm)
垢版 |
2020/05/10(日) 23:20:27.99ID:Z3WQBr9X0
!extend:checked:vvvvv:1000:512
(新スレ立ての際上記コマンドを2行書き込んでください)
C言語の話題のみ取り扱います C++の話題はC++スレへ
質問には最低限の情報(ソース/コンパイラ/OS)を付ける
数行で収まらないソースは以下を適当に使ってURLを晒す
https://paiza.io/
https://ideone.com/
http://codepad.org/

C11
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf

C99
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
http://kikakurui.com/x3/X3010-2003-01.html

C FAQ 日本語訳
http://www.kouno.jp/home/c_faq/

JPCERT C コーディングスタンダード
https://www.jpcert.or.jp/sc-rules/

※前スレ
C言語なら俺に聞け 154
https://mevius.5ch.net/test/read.cgi/tech/1578997950/
VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured
2020/09/15(火) 01:38:55.84ID:GcvmEeWM0
>>883
中身が空っぽなinputだったらどうする?
2020/09/15(火) 07:29:42.10ID:YjwP830M0
後判定といえば自明な弱点があるね
2020/09/15(火) 11:24:23.73ID:DboEcGlM0
>>884
はてなブックマークです。
https://b.hatena.ne.jp/entry/139652170/comment/rin51
888デフォルトの名無しさん (ワッチョイ eaad-pVuC)
垢版 |
2020/09/15(火) 13:34:11.71ID:2J2Mo0F/0
ま、しかし、よくよく考えてみると feof() って使い所がほとんどないのではないか?
fgetc() が文字だけでなく EOF まで返す仕様になっているから使わずにも書けてしまうよね。
単にEOFになった後かどうかだけを調べたい場合は fgetc() 使ったら無駄な処理になるけど。
889デフォルトの名無しさん (ワイーワ2 FF92-e6VR)
垢版 |
2020/09/15(火) 13:46:37.73ID:i/gZOuAlF
そもそも feof 使わないよね?って話題だし
2020/09/15(火) 14:02:51.06ID:pUsOBU6W0
fgetc()等はファイルを最後まで読み取った場合だけでなくエラーの場合もEOFを返すことになってるから
どちらの状況か区別するためにfeof(),ferror()はあるんだろ
区別しなくていいなら使わんわな
2020/09/15(火) 14:14:08.17ID:8CWM1WbO0
>>883
ダメダメって書いてあるやろ

rero
ferror の条件が成立した場合,feof の条件は成立せず,無限ループになる.
ループ脱出条件にはfread / fscanf / fgetc などの戻り値を使う.
feof は ferror との切り分けにのみ使う.
2014/02/04
2020/09/16(水) 18:30:21.50ID:+0jueX8G0
ありがとうございました。
893デフォルトの名無しさん (ワッチョイ d793-lMKa)
垢版 |
2020/09/17(木) 12:37:14.53ID:3L04nVD50
関数定義の書式『例えばprintf関数なら、 int printf(const char * format, ...) 』とかで、関数の引数の型指定が含まれてるけど、これの指す具体的な意味って何?
例えば、const char*型が指定されていたとして、
1、「const char*型でなければならない」
2、「他の型も使えるがconst char*型を推奨する」
3、「色々と対応してるけど代表としてconst char*型を挙げる」
4、「1〜3のうちどれか、関数毎にケースバイケースで具体的には決まってない」
関数定義の書式における型指定には、どのような意味が込められてるんですか?
printf関数では、普通に文字列を入れた配列のポインタ(char *型)にも対応してるので、2か3なんだろうけども。
関数定義書式に含まれる型指定は、1〜4のどれなのか、C言語では統一的に指針が決まってますか?
894デフォルトの名無しさん (ワイーワ2 FFdf-SP/v)
垢版 |
2020/09/17(木) 12:40:32.43ID:OW2OZx8DF
1
895デフォルトの名無しさん (ワッチョイ d793-lMKa)
垢版 |
2020/09/17(木) 12:50:38.33ID:3L04nVD50
printf関数の場合では、「char*型が使えるように見えるけど、色々と問題起きるからconst char*型以外は禁止」ということなんですか。
分かりました。
2020/09/17(木) 12:53:34.67ID:uk2B69G8M
const char*はchar*の指す先を書き換えないだけで同じものなのでconst char*をchar*で初期化してなんの問題もない。暗黙変換してくれる。
逆は書き換えられないconst char*が書き換えできる様になってしまうので暗黙にはしない様になっている。
2020/09/17(木) 13:02:01.33ID:9/9M+ZB20
こんなこともできるけどね
static /* const */ char str[] = "hello stupid people";
printf(str);
898デフォルトの名無しさん (ワイーワ2 FFdf-SP/v)
垢版 |
2020/09/17(木) 13:08:31.54ID:OW2OZx8DF
質問のレベルから忖度すると
質問者が気にしてるのは
ひょっとすると
...
の部分の方なのかも知れない
899デフォルトの名無しさん (ワッチョイ f77c-E8AY)
垢版 |
2020/09/17(木) 13:10:16.65ID:/CJv2N4s0
#include <stdio.h>

int main(int ac, char **av)
{
int p = 0x000a0d41;
printf((char *)&p);
return 0;
}
900デフォルトの名無しさん (ワッチョイ bf8c-CUqR)
垢版 |
2020/09/17(木) 13:40:44.35ID:PwEIVjdJ0
関数定義の引数が配列で書けるようになったのはいつから
int func(array[5]){
.......
}
2020/09/17(木) 13:45:22.35ID:9/9M+ZB20
型指定子がないけど暗黙intってことか? 無理だと思うけど
902デフォルトの名無しさん (ワイーワ2 FFdf-SP/v)
垢版 |
2020/09/17(木) 13:46:44.16ID:OW2OZx8DF
昔から
2020/09/17(木) 13:52:07.27ID:qRMpu/GI0
>>899
明示変換してるのに暗黙変換もさせるのは読みづらいよ
2020/09/17(木) 13:55:11.12ID:9/9M+ZB20
つーかさ
pにアドレス演算子つけてるの
何かがわかってない兆候じゃね?
905デフォルトの名無しさん (ワッチョイ d793-lMKa)
垢版 |
2020/09/17(木) 14:31:37.44ID:3L04nVD50
皆さんのレスを行間を読んでまとめること、こんな感じの理解でいいですか?

代入の際、右辺の値は、左辺の型に暗黙変換される。
int a = 3.5; // duble型リテラルを暗黙変換してaには3が入る
int a = 'a' // const char型?リテラルを暗黙変換してaには文字コードを表す97が入る
int a ="ほげ"; // const char型リテラルを暗黙変換してaにはよくわからん不正値が入る
同様に、関数へ引数を渡すことも代入の一種であり、実引数が代入する側であるから代入式の右辺に相当し、仮引数が代入される側であるから左辺に相当する。
その際、実引数char*型は仮引数const char*型へ暗黙変換される。
int main(void) {
char hoge[] = "ほげ";
printf(hoge); // 実引数hogeは先頭要素を指すポインタchar*型で、暗黙変換を伴って仮引数のconst char*型となる
}
この逆、仮引数char*型に実引数const char*型を渡すのはNG。char*型とわざわざ指定されてる理由は、値を書き換え可能なポインタを求めるためであり、const char*型はダメ。
2020/09/17(木) 14:32:12.65ID:FojOL81h0
>>900
型が書かれていないけどそれはタイプミスだとすれば、
配列形式で仮引数を書くこと自体は昔から出来る。
ただし、配列形式で書かれるとそれはポインタに調整される。

たとえば仮引数が int array[5] だったら int* array と全く同じとみなされる。
配列の大きさの情報は無視される。
(ひょっとすると警告を出すためのヒントにするくらいの処理系はあったりするのかもしれんけど。)
2020/09/17(木) 14:42:51.44ID:FojOL81h0
>>905
暗黙の変換がされる場合とされない場合はあって、

int a ="ほげ";

で暗黙の変換をする保証はない。
C99 だと単純代入で許される型の組み合わせは 6.3.16 に書かれている。

処理系の拡張としてやっちゃうこともあるかもしれんけど、
その場合でも警告は出るんじゃないかなぁ。

> 関数へ引数を渡すことも代入の一種であり

その通りだが、関数原型 (プロトタイプ) がない場合や
可変長引数 (仮引数が ... で表されるやつ) の場合はちょっとルールが特殊な部分もある。

まちがっててもコンパイラが検出できないこともあるので気を付けないといけない。
2020/09/17(木) 16:23:39.93ID:9/9M+ZB20
処理系の拡張ねえ
gccは-pedanticつけないと黙って通す場合あるかんな

>>905
void func(char *);
func("const char array");
これconst違反なのにできちまう
909デフォルトの名無しさん (ワッチョイ bf8c-CUqR)
垢版 |
2020/09/17(木) 17:46:14.08ID:7hPXgG620
>>900
すまぬ訂正
関数定義の引数が配列で書けるようになったのはいつから
int func(int array[][5]){
.......
}
2020/09/17(木) 18:43:35.04ID:FojOL81h0
>>908
C の文字列リテラルは char の配列ということになっているので char* で受け取れる。
型の視点で見ればそのコードに const は登場しない。

文字列リテラルを書き換えようとした結果は未定義であるにもかかわらず
型に const が付かない C のクソなところのひとつ。

(C++ では文字列リテラルの型には const が付く。)
911デフォルトの名無しさん (ワッチョイ d793-lMKa)
垢版 |
2020/09/17(木) 19:21:07.83ID:3L04nVD50
よく見てみたら使ってるツールがC++用だった。
C言語入門本でインストールを促すソフトが大抵Visual StudioのC++で、
意識せずにC++の開発環境でC言語の勉強をしてたんだな。
それで、C言語の挙動だと思ってたのが、実はC++の挙動だったんだな。const の件もそう。
2020/09/17(木) 19:39:01.71ID:9/9M+ZB20
>>909
全然配列じゃないじゃん
int func(int(*array)[5]);
これと同じだよ、配列へのポインタ
2020/09/17(木) 19:55:04.93ID:+PkSrmT3M
いくら引数リストに要素数を記述してもコンパイラは無視する
int func(int **array)と同じ扱いでただのニ重ポインタ
2020/09/17(木) 19:57:19.31ID:9/9M+ZB20
>>913
アホwバカwww
2020/09/17(木) 19:58:54.02ID:9/9M+ZB20
char **aho = 0;
printf("%p ", aho);
aho++;
printf("%p ", aho);

printf("%p ", array);
array++;
printf("%p ", array);
916デフォルトの名無しさん (ワッチョイ d793-lMKa)
垢版 |
2020/09/17(木) 19:59:49.49ID:3L04nVD50
でもまあプログラムの再利用性を考えたら、constの件は、C++仕様に配慮して省かないことが大事か。
C++に配慮したコードを書くことで、C言語でもC++でも通用するプログラムとなり、プログラムの再利用性が上がる。
C言語ではconstを省くことが文法的には認められてても・・・・・C++に流用できないプログラムは、たぶんコードとしては減点となる。
2020/09/17(木) 20:03:53.36ID:FZAv8QRcM
>>914
いや、マジで関数に配列を渡せると思ってるの?
配列の引数はポインタの引数の糖衣構文だよ
どうしても配列を渡したい場合は配列を構造体で包めば要素数を関数に渡すことは出来る
2020/09/17(木) 20:05:11.15ID:FojOL81h0
>>913
いや、それは >>912 が正しい。
二重ポインタにまで調整されてしまうと
関数 func の中で array[1][3] みたいなアクセスが不可能になってしまう。
ポインタへの調整はあくまで一段階のみ。
2020/09/17(木) 20:08:22.99ID:FojOL81h0
>>917
配列を渡すのではなく「配列へのポインタ」だ。
配列は多くの場合に配列の先頭要素を指すポインタに暗黙に型変換されるけども、
それとは別に配列を指すポインタというものが存在し、
指す先の配列の大きさは型情報として保存される。
2020/09/17(木) 20:13:48.15ID:9q71Nrm0M
関数の引数として配列を渡す場合、アドレスと要素数は別に渡す必要がある
関数内で要素数を知る手段はない
int func(int **array, int i, int j)
2020/09/17(木) 20:14:06.25ID:FojOL81h0
int array[][5] という配列があったとしたら、その先頭要素の型は int [5] なので、
通常通り配列の先頭要素そ指す型に型変換したら int (*)[5] になるんだ。
仮引数の側もそれと同じような調整が入る。
2020/09/17(木) 20:19:02.57ID:9q71Nrm0M
それは配列の変数宣言の場合だ
仮引数の場合には当たらない
2020/09/17(木) 20:29:34.78ID:FojOL81h0
>>922
JISX3010:2003 から

> 6.7.5.3
> 仮引数を "〜型の配列" とする宣言は、 "〜型への修飾されたポインタ" に型調整する
2020/09/17(木) 20:31:16.69ID:JChOP/F3M
だから糖衣構文だと言ってるだろ
2020/09/17(木) 20:32:41.07ID:FojOL81h0
>>924
構文糖だよ。
でも >>913 の構文糖ではないって話をしてる。
2020/09/17(木) 20:53:29.25ID:+AujTTfU0
>>916
正直言って、const のありがたみが今一つよくわからないんですよね…
2020/09/17(木) 21:37:33.81ID:VrEKPYEi0
確認してみた
配列が仮引数の関数内で配列の型情報は失われて単なるポインタになってる

メイン関数内配列サイズ 20Byte (int[5] = 4Byte * 5)
関数内配列サイズ 8Byte (int* = 64bit)

https://i.imgur.com/nItgOZC.png
2020/09/17(木) 21:54:03.82ID:PVWtVfHXM
そう、仮引数の配列要素数はコンパイラに無視される
ただのポインタだから配列サイズは失われている
2020/09/17(木) 22:14:39.96ID:ysRkZn2Ya
>>926
うっかり変更しようとしたら、コンパイル時にエラーになるでしょ
2020/09/17(木) 22:35:38.61ID:qRMpu/GI0
>>927
909読め。一次元じゃなくていわゆる2次元配列な
sizeofに*付けるの忘れないように
2020/09/17(木) 22:46:13.06ID:FojOL81h0
修飾なしで const になって、変更可能な変数の場合に指定を付けるようになってればよかったのに
という声は一部では根強く有る。
もちろんそんな非互換な変更を C/C++ が受け入れるはずがないので
あくまでももしもの話というか愚痴の類なんだけど。

でも Rust がまさにそうなったので型の厳しさを指向するなら
デフォルトで変更不能な方が自然なのかもしれんね。

個人的には、 C で意識して const を付けるのは関数の仮引数くらいで十分だろう
という程度かな。 そのかわり仮引数の型付けはかなりしっかりしたい。
2020/09/17(木) 23:08:14.29ID:VrEKPYEi0
>>930
sizeofの間接参照の意味がよく分からんけど2次元配列

https://i.imgur.com/HNIrfoF.png
2020/09/17(木) 23:13:21.69ID:aQ5w/H9b0
リソースが極限まで制限されるような環境下で動かすことがる
ハードに近い部分を書くことが多かった
最適化の精度が悪かった
みたいな時代背景があるのでデフォルトがconstはナンセンス
もちろん今の時代に1から設計するならそういう言語が出てくるのは当然
2020/09/17(木) 23:27:44.50ID:qRMpu/GI0
>>932
sizeof(*array)だよ
2020/09/17(木) 23:46:44.97ID:cQbuW7S9M
>>932
>>913は間違いでvoid func(int array[][5]) と void func(int **array) では意味が違うって話だから
それぞれfuncで sizeof(*array) を見ないと意味ない
2020/09/18(金) 00:25:49.56ID:InePzAsW0
普通に array[1][3] みたいにして要素にアクセスするときでも
規格上の理屈では *(*(array+1)+3) の構文糖であるということになってて、
じゃあこれを成り立たせるにはどういう型情報があればいいのか
みたいな方向でパズル的に考えて遊んだりするのも面白いかもね。

あとここまでのやりとりで出てきてないっぽいから注意点を示しておくけど、
配列が暗黙の型変換でそれの先頭を指すポインタになるルールの例外が
sizeof を適用したときと単項 & を適用したときだよ。
2020/09/18(金) 06:03:42.05ID:dDojkzke0
sizeofと&が例外って言い方よく見かけるけど
気持ちの中ではこっちが本来だね

extern int array[]; と
extern int *array; じゃ
意味違うし
2020/09/18(金) 06:28:13.21ID:n6muJc1p0
>>933
> リソースが極限まで制限されるような環境下で動かすことがる
> ハードに近い部分を書くことが多かった
> 最適化の精度が悪かった
なんの理由にもなってないと思うが…
単にK&Rがそう言うのに無頓着だっただけだろ
2020/09/18(金) 06:31:46.59ID:dDojkzke0
何の理由にもなってないのはそのとおりだが
なんで無頓着って話になるんだ?
アセンブラで書いていたUnicsを高級言語で書けるようにしようって作ったんだぜ?
2020/09/18(金) 09:01:10.98ID:InePzAsW0
>>937
確かに。

暗黙の型変換の方を中心に説明したから例外という言葉を使ったが、
配列がポインタになる方がよっぽど特殊な話だよな。
2020/09/18(金) 09:11:41.22ID:dDojkzke0
初心者がややこしい規則をこれから憶えようってときには
確かにあの言い方は情報量少なくて憶えやすそうだけど
初心者を卒業したらいつまでもしがみついてると格好悪いね
2020/09/18(金) 10:09:00.07ID:n6muJc1p0
>>939
例えばintとポインタの扱いとかみたら結構無頓着だと思わない?
別にそれが悪いと言ってるわけじゃない
高級アセンブラとしてはまあ理解出来なくないし当時のマシン環境の制約もあっただろうしね
943デフォルトの名無しさん (エムゾネ FFbf-SP/v)
垢版 |
2020/09/18(金) 10:37:02.65ID:6n8VMUNiF
ラクッペペ MM8f-kMIc

こいつは無視でOK
2020/09/18(金) 12:10:56.45ID:3NbVdp1XM
そんな感じの2次元配列の引数としてはかけるけど
実際その関数になに代入してもエラー吐くやつとかあったな
2020/09/18(金) 12:52:30.78ID:dDojkzke0
関数に代入ってどゆこと?
2020/09/18(金) 12:54:19.87ID:dDojkzke0
>>942
> 例えばintとポインタの扱いとかみたら結構無頓着だと思わない?

intをポインタにキャストするようなこと?
2020/09/18(金) 16:08:04.83ID:3NbVdp1XM
>>945
引数になにいれてもだった
2020/09/18(金) 20:15:43.21ID:dDojkzke0
こういうこと?
void func(int (*array)[5], int **pointer)
{
char a[2][5], *p;

array = a; //ok
pointer = a; //error

array = &p; //error
pointer = &p; //ok
}
2020/09/18(金) 23:38:09.01ID:InePzAsW0
>>947
逆に、引数に何を与えても許容してしまうという事例は今でも簡単に書けるね。

https://wandbox.org/permlink/uv5dmsN9NA58k8Wp
2020/09/19(土) 09:21:06.58ID:FHaFE8730
あ、すまんw
s/char/int/g
2020/09/19(土) 11:02:59.46ID:Uw1s41Nc0
>>949
そうだけど、それは「危険性」には繋らんよな?
引数関連の危険性というのは大抵、
引数を変に実行してしまうことから始まる訳だから。
2020/09/19(土) 13:13:28.09ID:cxOsPIuF0
>>951
一応は >>949 も未定義だよ。
呼出規約が cdecl だったら余計な引数は捨てられるだけで問題にならないとは思うけど。

余計な引数を渡すのとは逆に必要な引数を渡さないという例も書けるから、
より危険性がわかりやすいかな。

https://wandbox.org/permlink/1F876xK6UZ4wFjAA

余談だけど関数定義は宣言も兼ねるというルールにおいて、
K&R スタイルの関数定義はプロトタイプを持たない宣言でもあるという扱いだから
別途プロトタイプ宣言をする分にはエラーとして検出される。

https://wandbox.org/permlink/4n574f4R9yq0BzUj
953デフォルトの名無しさん (ワッチョイ 7f28-5uLG)
垢版 |
2020/09/19(土) 14:57:40.15ID:Uw1s41Nc0
>>952
> 余計な引数を渡すのとは逆に必要な引数を渡さないという例も書けるから、
たしかにその通りだな。

>>949 のコード例に気をとられて
もとの議論の内容を忘れてたw

thx
2020/09/19(土) 14:57:50.91ID:Uw1s41Nc0
すまんsage
2020/09/21(月) 03:21:46.70ID:SqQ7e3H60
>>952
普通先行宣言をちゃんとするだろ
2020/09/21(月) 08:57:54.77ID:sulqQktu0
>>955
普通はする。 すべきだ。 というのがどれほどあてになるか。

普通はすることを (うっかり) しなかったら (エラーとして検出されずに) 通ってしまうってのは
K&R スタイルの関数定義はイケてないねって話。
2020/09/21(月) 08:59:37.43ID:sulqQktu0
K&R スタイルでなくともファイルを分割すると宣言と定義の矛盾が検出されなかったりもする。

// foo.c
void foo(int x) {
}

// foo.h
void foo(void);

// main.c
#include "foo.h"

int main(void) {
foo();
}

このとき foo.c をコンパイルするだけなら foo.h は不要だが
foo.c で foo.h をインクルードしておかないと間違いは検出できない。
958デフォルトの名無しさん (アウウィフ FF5b-SP/v)
垢版 |
2020/09/21(月) 10:49:53.26ID:M8W5JifWF
linkエラーは?
2020/09/21(月) 11:10:21.40ID:WONfy98d0
>>958
大抵の処理系ではリンクエラーにならないよ
C言語だとコンパイル後は引数の情報は無くなっちゃうから
960デフォルトの名無しさん (アウウィフ FF5b-SP/v)
垢版 |
2020/09/21(月) 11:19:45.80ID:M8W5JifWF
実行時にスタック壊れたり
hangupしたりするんです?
2020/09/21(月) 12:59:37.93ID:sulqQktu0
>>958
C のオブジェクトファイルは名前しか保存しておらず、
型はヘッダファイルでやりとりするというのが伝統的なデザイン。
だからそれを一致させるのはプログラマの責任。

現代の実装技術なら検出できないことはないはずなんだが、
検出しないのは色々な都合があるんだろう。

>>960
cdecl や fastcall なら関数を呼び出すだけならスタックの整合性が壊れることはないと思うんだけど、
実引数と仮引数がまともに対応付けられていないわけだから
仮引数の読み書き (特に書き込んだとき) には壊れる可能性が高いんじゃないかな。
2020/09/21(月) 17:40:26.50ID:PNFNM3Vd0
> 現代の実装技術なら検出できないことはないはずなんだが、

ちゃんとやってるよ
外部参照名の長さの上限を増やすという
後方互換性を損なわない賢いやり方で

それの恩恵を有り難く頂戴しているのがC++
2020/09/21(月) 20:06:59.96ID:CAa9Vr4hM
意味わからん
マンダリングしてるC処理系なんてあったっけ?
別にオブジェクトコードに含ませなくてもデバッグ情報に含ませといてチェックするとかでも良いと思うけどね
2020/09/21(月) 21:16:44.87ID:PNFNM3Vd0
s/マンダリング/マングリング/g
2020/09/21(月) 21:27:28.62ID:r8sxqPhqM
>>963
32bitWindows向けのstdcallは引数等で使うスタックサイズを名前の後ろに付け加える
966デフォルトの名無しさん (ワッチョイ 9f47-SP/v)
垢版 |
2020/09/22(火) 02:46:33.89ID:EwzeVKsQ0
本人が間違ってる分には無視すれば良いだけだが
初心者スレで嘘を撒き散らすのは良くないな
2020/09/22(火) 09:19:28.05ID:73EWHT9ca
volatileオブジェクトへのアクセスは副作用を生じるというのを見たことがあるのですが
この場合の副作用とは具体的にはどういう事象のことを言っているのでしょうか?
2020/09/22(火) 09:29:18.39ID:GaogVwml0
>>967
具体例としては、 volatile なオブジェクトへのポインタを通したアクセスをメモリマップドI/Oと対応させることが多い。
https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%9E%E3%83%83%E3%83%97%E3%83%89I/O
2020/09/22(火) 11:37:01.89ID:duZr+LV8M
>>967
遅くなることがあるということかな?
2020/09/22(火) 12:21:55.75ID:73EWHT9ca
>>968
レジスタなどにアクセスする際に最適化で誤動作しないようにvolatileを付けるのかなと思ったのですが、
逆にvolatileを付けることによる不都合(副作用)って何かあるのでしょうか
それとも最適化されないことを副作用と読んでいるのでしょうか

>>969
最適化しないことによる処理時間増加でしょうか
2020/09/22(火) 12:26:59.11ID:ZRR+59kRa
最適化によって、本来は必要な処理がコンパイラによって省かれてしまうとか
2020/09/22(火) 12:28:12.05ID:ZRR+59kRa
コンパイラの判断によって、一部のコードが生成されないとか
2020/09/22(火) 12:48:41.23ID:fNKq19I/0
>>970
プログラミングの世界の副作用とは、不都合とかそんな意味ではなくて、内部状態が変更されるとか、外に何らかの影響を与えるとかそんな意味だよ。

例えばisalpha関数は文字の判定をするだけだけど、printfはコンソールに文字を出力する。
前者は副作用なし、後者は副作用ありだね。

volatileの件はそれが書かれた前後のコンテキストが分からないから何を指してるのか何とも分からんけど、たぶん、>>968に書かれてるように、外部デバイスへの作用のことを指してるんじゃないかな
2020/09/22(火) 13:01:07.61ID:GaogVwml0
>>970
副作用 (プログラム)
https://ja.wikipedia.org/wiki/%E5%89%AF%E4%BD%9C%E7%94%A8_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0)
> プログラミングにおける副作用(ふくさよう)とは、ある機能がコンピュータの(論理的な)状態を変化させ、それ以降で得られる結果に影響を与えることをいう。

C言語における定義はこんな感じ。
http://kikakurui.com/x3/X3010-2003-01.html#13
> ボラタイルオブジェクトへのアクセス,オブジェクトの変更,ファイルの変更,又はこれらのいずれか
> の操作を行う関数の呼出しは,すべて副作用(side effect)と呼び(11),実行環境の状態に変化を生じる。
2020/09/22(火) 17:15:02.44ID:73EWHT9ca
回答ありがとうございました
組み込みの資料か何かでvolatileの副作用についての記述があり質問させていただきました
副作用の意味がいまいち分かってないみたいなので勉強します
2020/09/26(土) 02:24:05.62ID:AJ59WF/j0
int main(double a, double b)
{
printf("main");
}
2020/09/26(土) 02:27:39.44ID:80lZAyo5a
コンパイル通るのかな….
2020/09/26(土) 05:50:57.90ID:JvTrRG8q0
(void)と(int, char**)以外は処理系定義
コンパイラが対応していれば適格
対応していなければ未定義
2020/09/27(日) 13:50:39.37ID:LQE5yA3hM
crtstartupのお仕事だからコンパイラほぼ関係ないな
大抵の実用リンカは差し替えできるでしょ
980デフォルトの名無しさん (ワッチョイ f793-raSa)
垢版 |
2020/09/28(月) 07:00:27.18ID:BXhKM0Xn0
数値リテラル「0」の型は何ですか?

int* p = 0; // これはOK
int* p = (int)0; // 明示的にint型にしてから渡すと「int型はint*型に変換できません」とエラー。ということは、この 0 はint型以外?
int* p = (unsigned int)0; // これもエラーで無理。
printf("%zu", sizeof(0)); // 0の型のサイズを調べると4byteと表示される。
この数値リテラルの「0」の型は何ですか?
ちなみに、まだC言語環境を構築してないから、代わりVisualC++を使ってるけど、他の環境でも起きますか?
981デフォルトの名無しさん (ワッチョイ f793-raSa)
垢版 |
2020/09/28(月) 07:30:53.01ID:BXhKM0Xn0
さらに調べると・・・・
キャスト演算子で型を指定した0は、代入の際にint*型へ変換してくれない。
接尾語を付けて型を指定した0は、代入の際にint*型に変換してくれる。

int* p = (long int)0; // NG
int* p = 0L; // OK

int* p = (unsigned int)0; // NG
int* p = 0u; // OK

キャスト演算子で型を指定すると、代入の際の暗黙的な変換が禁止される仕様とかあるんですか?
2020/09/28(月) 07:54:15.67ID:QxfbhGyV0
>>980
intだよ

D:\learn>gcc --version
gcc (Rev2, Built by MSYS2 project) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


D:\learn>gcc 980.c

D:\learn>gcc 980.c -pedantic -Wall
980.c: In function 'main':
980.c:9:10: warning: unused variable 'p3' [-Wunused-variable]
9 | int* p3 = (unsigned int)0; //
| ^~
980.c:8:10: warning: unused variable 'p2' [-Wunused-variable]
8 | int* p2 = (int)0; // ntintnt*nt
| ^~
980.c:7:10: warning: unused variable 'p1' [-Wunused-variable]
7 | int* p1 = 0; // K
| ^~

-Wallにするとunusedって警告でるけど型の話じゃないね
2020/09/28(月) 08:00:54.96ID:QxfbhGyV0
>>981
D:\learn>cl 980.c /W4
Microsoft(R) C/C++ Optimizing Compiler Version 19.27.29111 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

980.c
980.c(8): warning C4047: '初期化中': 間接参照のレベルが 'int *' と 'int' で異なっています。
980.c(9): warning C4189: 'p3': ローカル変数が初期化されましたが、参照されていません
980.c(7): warning C4189: 'p1': ローカル変数が初期化されましたが、参照されていません
980.c(8): warning C4189: 'p2': ローカル変数が初期化されましたが、参照されていません
Microsoft (R) Incremental Linker Version 14.27.29111.0
Copyright (C) Microsoft Corporation. All rights reserved.

/out:980.exe
980.obj

参照されていませんという警告は型の話ではないのでここではスルー
型についての警告が出ている8行目とやらはこれ
> int* p2 = (int)0; // 明示的にint型にしてから渡すと「int型はint*型に変換できません」とエラー。ということは、この 0 はint型以外?

隣の9行目は警告されていない(しかも/W4で)
> int* p3 = (unsigned int)0; // これもエラーで無理。

おそらくclが警告しているのはXXX*とXXXでポインタの間接段数を間違えたんだろうということ
これなら9行目はXXX*とYYYで間接段数の問題ではないので黙っているという説明がつく
2020/09/28(月) 08:46:00.83ID:E0ldxkXM0
0だけは特別にポインタにキャスト可能な仕様なんじゃよ
0がいい 0になろう
レス数が950を超えています。1000を超えると書き込みができなくなります。
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況