C言語なら俺に聞け 163

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん (ワッチョイ 7bba-Lem2)
垢版 |
2024/07/16(火) 22:43:54.18ID:ZrsCjURC0
!extend:checked:vvvvv:1000:512
(新スレ立ての際上記コマンドを2行書き込んでください)
C言語の話題のみ取り扱います C++の話題はC++スレへ
質問には最低限の情報(ソース/コンパイラ/OS)を付ける
数行で収まらないソースは以下を適当に使ってURLを晒す
https://paiza.io/
https://ideone.com/
http://codepad.org/

C17
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf

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

C23 最新ドラフト
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.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言語なら俺に聞け 162
https://mevius.5ch.net/test/read.cgi/tech/1698653580/
VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured
2024/09/14(土) 18:13:05.20ID:5H/bnNk90
はちみつ餃子の説明はたぶん、C++ の考え方が混ざっていないか
C で配列の初期化子に文字列リテラルが書けるのはあくまで文字列リテラル限定であって、それは式として扱われるのではなく、lvalue も rvalue もクソもないということだと思うが
2024/09/14(土) 18:35:19.29ID:N2YvcTj50
>>154
初期化子の文法の一部であって式の規則の適用範囲外じゃないの?ってことだよね?
6.7.8 を見てこの場合でも式だと解釈してるけど、そういわれたらちょっと自信がないかも。
2024/09/14(土) 18:53:38.72ID:0gsw2riP0
>>153
その配列に格納されているデータが文字列リテラルから生成された文字列(の実体)だろ
厳密に言いたいなら、文字列リテラルはコンパイル時に存在さえしてれば良いものなんだよ
何しろ「リテラル」だから
それを生存期間だの実行時の実体とごっちゃにしてるから訳分かんないことになんだよ
コンパイル時にさえ存在してれば良いという事を実行時には消えてても良いとか言っちゃってんでしょ?
2024/09/14(土) 19:03:33.67ID:0gsw2riP0
char foo[] = { 'h', 'o', 'g', 'e', 0 };
文字列リテラルは↑のシンタックスシュガーだ
初期化子は消えても構わないのか?
初期化子が生成した文字列は参照出来ないと言うのか?
2024/09/14(土) 19:10:37.88ID:5H/bnNk90
>>155
https://en.cppreference.com/w/c/language/array_initialization
ここ参考にしてたから文法定義の時点で式じゃないと思ってたけど、ちゃんと規格上は式としてのパースではあったね、すまない
改めて C99(でいいんだよね、6.7.8 ってことは)の draft 読んでみたけど、文字列リテラルで初期化できるのは 6.7.8.14,15 で特殊に定義された意味論であって、やっぱり式扱いじゃないんじゃないかね
2024/09/14(土) 19:58:20.45ID:N2YvcTj50
>>154
結果的な挙動からするとどっちでも良いから書いてないだけかも。
2024/09/14(土) 20:16:47.07ID:8t7wdnSS0
皆拘らずに使っているのに言うのもあれなんだが
C言語にはC++で言う参照はありません
2024/09/14(土) 21:01:12.02ID:NQ2pFzob0
hogeは破棄されないって一人がんばってるID:0gsw2riP0を救済して差し上げたいが……自分も完全にわかってないのでできない。
2024/09/14(土) 21:04:22.62ID:tDLmxNl+0
実在するのはfoo[]だけで
文字列"hoge"は破壊どころか最初からあっても無くてもいいというのがここまでにわかったことだろ
163デフォルトの名無しさん (ワッチョイ 7910-VVra)
垢版 |
2024/09/14(土) 22:15:49.35ID:zMI9sEnq0
配列と別に文字列もどこか別に確保しといて何の意味があるんだよ
この形で配列作る度に二倍メモリ食うことになるじゃないか
2024/09/14(土) 22:32:05.03ID:N2YvcTj50
>>163
せやで。 だから最適化の余地があるという話をしてる。
2024/09/14(土) 22:34:31.27ID:8t7wdnSS0
ここで最適化の話は混ぜない方が良い
2024/09/14(土) 23:00:09.33ID:0gsw2riP0
>>163
clangは配列でも文字列リテラルは残ってるよ
ここって想像だけで語るアホばっかだなw
リテラルはコンパイル時のみに必要
それとは別に実行時にリテラルを実体化した値が存在する
基本的にrvalueだ
でないと当然初期化が出来ない
この値をはちみつは無視して語っている
2024/09/14(土) 23:04:40.23ID:0gsw2riP0
はちみつはリテラルはコンパイル時にのみ必要な事と、実行時には必要な初期値(rvalue)を最適化で命令コードに埋め込む事を消えたと表現して、ごっちゃにしてるアホ
これが結論
2024/09/14(土) 23:11:36.67ID:0gsw2riP0
リテラルは参照されないと言ってるのがその証拠
そりゃコンパイル時にのみに必要なその場でデータ構造を表現するリテラルを、実行時に参照出来る訳ないだろw
それが出来るのはコードをデータとして表現してるLisp だけだ
C++のテンプレートでも無理
C++のconstevalなら可能になった
std::formatはそれで実装可能になった
実行時には初期化の為のrvalueが絶対に存在する
2024/09/14(土) 23:13:53.14ID:0gsw2riP0
constevalも文字列リテラルを参照可能なのはコンパイル時のみだった…
やっぱり真に実行時に文字列リテラルを参照可能なのはLisp だけだな
2024/09/14(土) 23:40:13.14ID:5H/bnNk90
>>1 の C17 ドラフトのリンク C++17 のやつじゃん
次スレ立てるならこれに変えといて

https://web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
2024/09/14(土) 23:53:27.27ID:N2YvcTj50
>>167
起きていることは >>127 でこれ以上なく具体的に説明されてるんだから改めて厳密に表現しないと理解できないとは思わなかったんだよ。

>>168
文字列リテラルが静的記憶域期間を持つことは 6.4.5 に書かれてる。
実行フェイズに存在するオブジェクトだよ。 (最適化を抜きにして仕様通りに解釈すれば。)

配列の初期化子として現れる文字列リテラルの扱いは微妙かもという話が >>154 >>158 の指摘だが、
記憶域期間についての記述は文脈を指定せず文字列リテラル全部を対象にした記述に見える。
2024/09/15(日) 00:57:56.19ID:/wZr5+b/0
>>163
そりゃ書き換える場合があるからでしょー
一個しかなかったら関数呼ばれるたびに初期値も書き換わってしまう
なんで悩んでるのこの人?
constつけたら一個ですむだろ多分
2024/09/15(日) 01:17:55.27ID:STy65/7c0
>>171
> 実行フェイズに存在するオブジェクトだよ。
存在してんじゃねーかよ!
これが最適化で消えて良いかの話だよ!
gccの場合は命令コードに埋め込んでるけど、消えてる訳じゃないし、別のポインターから参照可能だ
2024/09/15(日) 01:30:47.17ID:B6k8li/O0
>>173
配列とその初期化子として現れる文字列リテラルが別の存在だってことが俺が何度も書いてることだよ。
これがそんなに何度も何度も何度も何度も書かないと理解できないようなことか?
別のポインタは配列を指せるが、その初期化子として現れる文字列リテラルを指せるわけじゃない。

char* foo = "hoge";

のようなケースではポインタ foo は文字列リテラルを指してるということと対比しての話だぞ。
2024/09/15(日) 01:32:35.13ID:STy65/7c0
ちなみに「文字列リテラル」が「実行時」に存在してる訳では全くない
はちみつはそこを勘違いしてる
静的記憶期間というのはスコープの事だ
まぁエクステントと言った方が正確だが
それはコンパイラーが理解できるものだが、それと「実行時」に存在する値を結びつけてはいけないし関係無い
DLLだとしたら静的記憶期間の変数も実行時には存在しない可能性もある
スレッドローカルストレージの変数もそうだな

要するに文字列リテラルで生成されたデータは実行時には確実にアクセス可能で、消えてるなんて全くあり得ない
それをずっと言ってる
2024/09/15(日) 01:38:12.52ID:STy65/7c0
>>174
> 文字列リテラルを指せるわけじゃない。
はい、これが間違いの全て
文字列リテラルはコンパイラーだけが理解できる「構文」に過ぎない
それを実行時にさせないとはこれいかに?w
文字列リテラルは「実行時」には何て名前になってんだ?
配列でもないぞ
配列に代入される前のrvalueの事だ
まぁ文字列は例外的にlvalueにもなれるが、rvalueであることには違いない
2024/09/15(日) 01:45:15.62ID:hg9QOZOF0
>>171
なんかいろいろ書いたけど最終的には自分もそれで合っていると思う
実用上は正直どこで役に立つのかあまり思いつかないが、規格上どういう建て付けになってるのかはとりあえず理解できたかも
というか、実用上あんまり役に立つわけじゃないから今まで調べもしなかったというか

規格上は「リテラル」は存在せず integer/enumeration/floating/character は定数なんですね
それで定数は記憶域期間を持たない
文字列リテラルは静的記憶域期間を持つ
複合リテラルは関数本体の外か中かに応じて静的/自動記憶域期間を持つ、と

うーんでもなあ
某言語でいきなり &1 とか書けるの知ってたら別に定数にも記憶域期間持たせればいいじゃんとか思っちゃうなあ
とりあえずそうなっているというだけか
2024/09/15(日) 01:46:17.50ID:B6k8li/O0
>>175
> 静的記憶期間というのはスコープの事

ちがう。 記憶域期間はオブジェクトの寿命の区分。
6.2.4 を参照のこと。
寿命の区分が設定されている以上はオブジェクト (メモリ上のどこかにある) のこと。

> 文字列リテラルで生成されたデータは実行時には確実にアクセス可能で、消えてるなんて全くあり得ない

関数 (C のプログラムは関数の集合なので実質的にプログラムの全て) はオブジェクトではない。
私が「消える」と表現したのはこの意識があったからだが、機械語のレベルでどこかには存在するという意味ではそりゃ存在するだろう。
(同じ内容が連続する配列だったらループで書き込むような形にすることもあるかもしれない。)
配列の初期化子としての文字列リテラルは本来あるべき場所 (オブジェクト) から最適化で消えてるし、ポインタで指すことは出来ない。
2024/09/15(日) 01:53:34.48ID:B6k8li/O0
>>177
C++ の右辺値参照も左辺値参照も左辺値なんだよね。
参照を経由したら左辺値になるなら最初からそう出来ないか? と思ったことはある。
2024/09/15(日) 01:58:39.53ID:STy65/7c0
>>178
> ちがう。 記憶域期間はオブジェクトの寿命の区分。
だからエクステントと書いてんだろ!
もしかして理解出来なかったか?

> 配列の初期化子としての文字列リテラルは本来あるべき場所 (オブジェクト) から最適化で消えてるし
本来あるべき場所(オブジェクト)って何だよ?!
目茶苦茶だなw
これがコンパイラーと実行時に存在すべき値(rvalue)をごっちゃにした成れの果てだなw
2024/09/15(日) 02:33:43.11ID:STy65/7c0
初期化に使われた(文字列)リテラルが実行時にrvalueになったものに名前を付けるべきだな
これは最適化でも消えることはない(当たり前だが…)
名前がないとまたリテラルは消えるから参照出来ない野郎が発生しかねないw
182デフォルトの名無しさん (スッップ Sdbf-2MD7)
垢版 |
2024/09/15(日) 12:24:08.15ID:WkBCL5VYd
>>174
>char* foo = "hoge";

>のようなケースではポインタ foo は文字列リテラルを指してる

その表現が間違ってる。
fooは静的記憶域を指してるが正しい。

intptr_t *bar = 0xAABB;
この場合数値リテラルを指すなんて言わんだろ。
2024/09/15(日) 13:50:20.31ID:krajCak80
>>char* foo = "hoge";
>>
>>のようなケースではポインタ foo は文字列リテラルを指してる

>その表現が間違ってる。
>fooは静的記憶域を指してるが正しい。

彼も文字列リテラルは静的記憶域に置かれると言ってなかったっけ
僕にはこの2つの違いが分からないや
勘違いだったらごめんなさい
2024/09/15(日) 16:04:15.59ID:7leD3hDGM
もっと中身のある話しようぜ
2024/09/15(日) 17:53:23.56ID:V70NGKYC0
>>68
規格に後置++演算子は実数型とポインタ型にしか使えないとあったけどそれの関係じゃないの?
規格でそう決まってるだけの話では?
186デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/15(日) 18:13:20.02ID:/tCGodXOd
それだな
2024/09/15(日) 21:42:32.09ID:/wZr5+b/0
ちなみに
int main(int argc, char *argv[])
と定義しても
argvは++できる
2024/09/15(日) 23:27:23.69ID:dUpBu3ui0
main の引数だけど、人によって好みがある
*argv[]だったり、 **argvだったり、
さすがにargv[][]はいないと思う
2024/09/16(月) 08:22:23.81ID:JwEVxA0h0
>>185
配列はポインタに型変換される。 だから型は合うんだよ。
変更可能な左辺値でなければならないという制約に違反してる。
2024/09/16(月) 08:28:07.90ID:JwEVxA0h0
>>182-183
静的記憶域期間ってのは静的+記憶域期間なんだよ。 静的記憶域+期間じゃないんだよ。

まあ静的記憶域期間を持つオブジェクトが配置されている場所を静的記憶域と呼んでもカジュアルな場面ではそんなに不自然ではないとは思うけど。
実装上は専用のセクションに配置するのが普通だし。
2024/09/16(月) 08:30:39.50ID:+a4Swf1f0
ここまでのまとめ

Cは生産性が低い
C使いも生産性が低い
2024/09/16(月) 10:51:57.39ID:yKwOC4kA0
ID:+a4Swf1f0 は、言語に何使おうと生産性が低そう
193デフォルトの名無しさん (ワッチョイ ff2a-48Tr)
垢版 |
2024/09/16(月) 11:29:42.22ID:0nzerU0W0
>>191,192
生産性など、君ら社畜を計る尺度に過ぎんよ。
芸術家は、時間をかけて1行の美しさを追及するものだ。
2024/09/16(月) 12:43:08.20ID:T6H9+ne50
>>189
変更可能な左辺値に配列型は含まれないからそれとは違うん?いつポインタに型変換されてんの?
2024/09/16(月) 13:26:14.08ID:JwEVxA0h0
>>194

6.3.2.1 より
> 左辺値がsizeof演算子のオペランド,単項&演算子のオペランド,又は文字配列を初期化するのに使われる文字列リテラルである場合を除いて,
> 型“〜型の配列”をもつ式は,型“〜型へのポインタ”の式に型変換する。

式として出てくる配列は一部の例外を除けば問答無用で変換されるので ++ のオペランドに配列が出てくるときも変換後のポインタ (rvalue) に対する演算 (実際には出来ないけど) として解釈されるということでいいと思う。
2024/09/16(月) 14:56:21.22ID:T6H9+ne50
>>195
配列オブジェクトの先頭の要素で左辺値じゃないって書いてあるな
ということは左辺値の式の中に出てくる配列は左辺値じゃなくなっちゃうということ?
なんでそんな仕様になったんだろうね
2024/09/16(月) 16:28:24.01ID:JwEVxA0h0
>>196
C には配列の要素を指すポインタとは別に配列を指すポインタというものもある。
こんなことが出来る。

int foo[10];
int (*bar)[10] = &foo;

このときの bar の型は int(*)[10] ということになるわけだが……。
型情報として長さが含まれるのはかえって邪魔だ。
大抵の配列を受け取る関数 (str系やmem系など) は配列の大きさが固定ではないから。
配列の先頭要素で配列を代表させる (それが簡単な記法にする) ほうが都合がよかったんじゃないかと思う。
配列全体をひとつの値として扱いたい場合のほうが少ないだろうという判断もそれなりに合理的じゃないかな。

いまどきの言語 (Go とか Rust とか) は範囲を表すスライスという概念を導入して解決してるけど、
C の登場時期だと 2 ワードのオブジェクトを基本型にするのってなんかヤじゃない? と思ったとしても仕方ない。
198デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/16(月) 17:22:11.94ID:udznqyd1d
>>190
横からすまんが、記憶域期間って言葉も変
199デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/16(月) 17:23:46.99ID:udznqyd1d
>>189
>配列はポインタに型変換される。

それは関数呼び出しの場合だぞ
2024/09/16(月) 17:29:54.17ID:E0fXFEgV0
この糞コテは半端知識のかまちょだからNGやスルー推奨
2024/09/16(月) 18:10:03.54ID:JwEVxA0h0
>>199
こっちは根拠になる規格の文面を提示してるんだから違うというなら違うと思う根拠を提示して。
2024/09/16(月) 18:57:26.00ID:ISRAyNkZa
>>188
そらargv[][]では誤りだもんな
203デフォルトの名無しさん (アウアウエー Sadf-N1Zj)
垢版 |
2024/09/16(月) 21:32:46.16ID:NNTpe0yPa
>>187
たしかに関数の引数だと違うんだな
https://ideone.com/MR7Vqm
#include <stdio.h>

char *hoge(char fuga[10])
{
++fuga;
return fuga;
}

int main(void) {
char hage[10] = {0};
char *p = hoge(hage);
printf("%p, %p\n", hage, p);
return 0;
}

// もちろん ++hage は出来ない
https://ideone.com/xEP42d
204デフォルトの名無しさん (ワッチョイ bf4f-NiVF)
垢版 |
2024/09/16(月) 22:10:35.73ID:hHcIxSUD0
>>197
流石に言ってる事が的外れ過ぎるのでもうちょっと勉強した方がいいと思うよ
2024/09/16(月) 22:25:26.45ID:z+htC2pc0
恥ずかしながら、静的記憶域期間(で合ってるのか?)という言葉を知らなくて、ライフタイムは「静的」に含意されているのかと思ったワ…
しかし、記憶域期間って違和感あるなぁ
2024/09/16(月) 22:30:23.39ID:z+htC2pc0
わけわからん
>>205は撤回します
2024/09/16(月) 22:43:01.97ID:JwEVxA0h0
>>203
余談だけど配列だけじゃなくて関数型も関数ポインタ型に調整されるよ。
208デフォルトの名無しさん (ワッチョイ 9f7c-2MD7)
垢版 |
2024/09/16(月) 22:52:59.17ID:TDYyKtgo0
>>201
規格に配列は常にポインタに変換されるなんて書いて無いぞ。
2024/09/16(月) 23:00:53.05ID:f3T7KT8T0
>>208
「常に」とは書かれていない
「ポインタに変換される」ではなく「ポインタに型変換される」

>>102がまさにそれでしょ
E1という配列が関数呼び出しでない場合においてもポインタという型に変換されているから出来ること
2024/09/16(月) 23:10:52.64ID:yKwOC4kA0
>char *hoge(char fuga[10])

こう書いてあっても、関数内で10を使う訳ではない
関数内で仮に100個めの要素アクセスするロジック書いてもエラーにはならない
(実行時にはエラーになると思う、多分)

だから、
>char *hoge(char fuga[])
添え字無しにしても良いことになる
2024/09/17(火) 01:04:31.11ID:BokinMog0
>>210
元々ローカルでchar hage[10];と定義して10以上をアクセスしてもコンパイル時にはエラーにならないでしょ

引数に[10]と書くとしたら可読性のため(この関数では[0~9]までアクセスする可能性があると明示するため)
212デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/17(火) 10:15:58.36ID:9gub94Dsd
__FILE__ とか __LINE__ は大文字なのになんで __func__ は小文字なん?
213デフォルトの名無しさん (アウアウエー Sadf-N1Zj)
垢版 |
2024/09/17(火) 10:17:16.72ID:TMGdiCOOa
範囲の問題じゃなくて
++hage または hage++ が出来るか出来ないかが問題なんです
2024/09/17(火) 11:06:41.56ID:bX/ekV+z0
一見配列を受け渡ししているように見えるけれど、
実際はポインターとして受け渡ししているってことでしょ
2024/09/17(火) 11:56:03.91ID:FRc2ySeD0
>>212
__func__ はマクロではないからだと思う。
2024/09/17(火) 12:47:41.54ID:bX/ekV+z0
#include <stdio.h>

char hage[10] = {0};

char *hoge(void)
{
// ++hage; // error '++' には左辺値が必要です。
// return hage;
 return &hage[1];
}

int main(void) {
 char *p = hoge();
 printf("%p, %p\n", hage, p);
 return 0;
}
217デフォルトの名無しさん (アウアウエー Sadf-N1Zj)
垢版 |
2024/09/17(火) 13:07:46.14ID:TMGdiCOOa
>>214
そんなことは判ってるよ
(char hage[10]) で hage++ または ++hage 出来ちゃってる(ように観える)のが問題なんでしょ
関数の引数は (char hage[]) または (char *hage) のみにすれば良かった
(char hage[10]) はどうみても蛇足(結局境界テストされてないし)
2024/09/17(火) 13:11:47.81ID:bX/ekV+z0
問題だと思う人は、使わないようにしましょう
開発サイトでそういうルールを用意するのも手です
219デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/17(火) 17:17:11.73ID:9gub94Dsd
>>215
納得しました。
220デフォルトの名無しさん (ワッチョイ 9ffd-NiVF)
垢版 |
2024/09/17(火) 20:17:27.08ID:dLWvmxgr0
>>197
そもそもstr系mem系はアドレスを受け取るんであって配列を受け取る関数ではないっていう勘違いがあるんだけど
それはともかく大きさがどうのとかなんちゃらが都合がいいとか、本当にC言語でなんかプログラムを書いた事あるの?
221デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/17(火) 20:58:19.23ID:9gub94Dsd
俺は尻より胸派なんだよね。
2024/09/18(水) 00:42:28.78ID:wcwImUMc0
>>217
この場合に限らずcでは範囲チェックなどされないでしょ
必要なら自分でチェックするのが原則

void aaa(char hage[10],int idx)
{
if((UINT)idx < sizeof(hage)/sizeof(hage[0]))
printf("%d=%d¥n",idx,hage[idx]);
else
printf("%dは範囲外だhage¥n",idx);
}

これなら[10]に意味が出る
2024/09/18(水) 01:22:58.84ID:9DvoA/Ly0
ド素人w
2024/09/18(水) 05:59:54.60ID:Y3+kk9yU0
>>222

c faq 6.21 (英文が詳しい)
https://c-faq.com/aryptr/aryparmsize.html
>>207 の'調整'は'adjust'だろう
N1256を'adjust'で検索するのじゃ
Look, a new day has begun.
2024/09/18(水) 07:51:55.61ID:9Z5pFVfx0
8/16bit時代の1バイトでも、1ステップでも減らせってのを経験した人と
最近の可読性、移植性、安全性優先設計が当たり前世代とのギャップ。
2024/09/18(水) 08:59:57.51ID:9DvoA/Ly0
ギャップの問題じゃねーから
文脈すら理解できないじじいはすっこんでろ
2024/09/18(水) 09:30:25.30ID:Qk7JHPx80
専門板によくいるアスペだな
2024/09/18(水) 10:34:45.37ID:UYQxUcxO0
225 は釣りでしょう
2024/09/18(水) 13:08:51.24ID:eTGNACyx0
>>222
sizeof(hage) で配列のサイズが求まるの?
と思ったら、「char * (ポインタ)の大きさを返すよ」みたいな警告が @gcc
2024/09/18(水) 13:15:29.42ID:UYQxUcxO0
釣りだか天然だか、分からなくなってきた 笑
2024/09/18(水) 13:35:28.77ID:td/rS/wM0
今どきの統合開発環境を使ってるなら変数の型くらい見れると思うけれど
古典的な手法としてあえてエラーにしてメッセージを読むという型の確認方法がある。

void foo(char bar[10]) {}
int main(void) { int baz = foo; }

こんなコードをたとえば gcc でコンパイルを試みると

error: initialization of 'int' from 'void (*)(char *)' makes integer from pointer without a cast

というエラーになる。
foo の型が void (*)(char *) であることがわかる。
foo は関数型の式 (関数指示子) なので暗黙に関数ポインタに型変換されているのと
bar に相当する箇所の型が char* になってるのがわかる。
2024/09/18(水) 13:51:08.91ID:eTGNACyx0
なるほど
勉強になります
233デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/18(水) 14:54:11.13ID:LEoKOQZWd
>>222
>この場合に限らずcでは範囲チェックなどされないでしょ
>必要なら自分でチェックするのが原則

>void aaa(char hage[10],int idx)
>{
> if((UINT)idx < sizeof(hage)/sizeof(hage[0]))
> printf("%d=%d¥n",idx,hage[idx]);
> else
> printf("%dは範囲外だhage¥n",idx);
>}

>これなら[10]に意味が出る

printf("%uz\n", sizeof(hage)/sizeof(hage[0]));
の結果ってどんな値表示されるの?
234デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/18(水) 14:56:10.00ID:LEoKOQZWd
書式のとのuzじゃなくてzuだっけ?zだけでよかったっけ?
ま、主旨はそこじゃないからいっか。
2024/09/18(水) 15:47:33.09ID:3rwci13t0
>>233
sizeof(char*)/sizeof(char) ということになる。
sizeof(char) は確実に 1 だから結果としては単に char* のバイト数ってことだね。

この場合は「『もし 10 に意味があるとしても』境界チェックはされないことに変わりないのでなんの役にも立ってない。 役に立てるとしたらここまで書かなきゃならない」というのが主旨なのであくまでもしもの話。
実際の値はどうでもよい文脈だと思う。
2024/09/18(水) 16:33:08.44ID:wcwImUMc0
>>224
ああそうなの
昔のことだから記憶違いをしてたようだ
237デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/18(水) 16:43:30.74ID:LEoKOQZWd
>>235
>>222 の「これなら[10]に意味が出る」ってのは間違いってことね。
2024/09/18(水) 18:00:34.97ID:wcwImUMc0
'ここの10は意味ありませんよ'
って警告を出してもいいじゃんってことでしょ
それなら例えば

typedef char HAGE_TBL[10];
void foo(HAGE_TBL hage) {}
(毎回10とか書くのは危険なのでこういう使い方が多いと思う)

などとした場合に毎回警告が出てうざいことになるんじゃないか
2024/09/18(水) 18:07:31.49ID:UYQxUcxO0
警告ならまだ笑っていられるが、
明らかに書いた奴の意図とは違って誤動作してるだろ
240デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/18(水) 18:30:29.69ID:LEoKOQZWd
>>222 のバグを晒すスレはここですか?
241デフォルトの名無しさん (スプッッ Sd3f-2MD7)
垢版 |
2024/09/18(水) 18:46:04.44ID:LEoKOQZWd
C言語は難しいな
2024/09/18(水) 20:53:02.12ID:UYQxUcxO0
void aaa()の中で、
引数で渡された値が何かを確かめて見ると良い
それと、 sizeof(hage)やsizeof(hage[0])の値も

プログラム書いた人の意図としては、
sizeof(hage)/sizeof(hage[0])が10になるはずなんだが
さてさていくつだろうか?
243デフォルトの名無しさん (ワッチョイ 9f7c-2MD7)
垢版 |
2024/09/19(木) 00:15:21.84ID:5H+5PGV10
もうやめて!>>222 のライフはゼロよ!
2024/09/19(木) 06:32:15.59ID:zdFAvN1E0
本人が新たなネタを出してくるんだもん。
>>238 でもわざわざ
typedef char HAGE_TBL[10];
ってやっておきながら、なんで
void foo(HAGE_TBL hage)
なの? 構造体と同じように
void foo(HAGE_TBL *hage)
ってしてみたら新たな何かが見えてこないかい?
2024/09/19(木) 15:36:15.62ID:bQAYIDF0M
cは洗練された型システム持ってないんだからそんなところ頑張っても無駄なんだよ
この悟りに至って始めて脱初級
原則語るならそれからにしてくれ
2024/09/19(木) 15:40:30.12ID:cPR7xA8Z0
Cは一部の洗練された型システム持つ言語よりも遙かに自由度が高い
そこが分かってようやく中級レベル
あとは本人の努力次第で空も飛べるし海も潜れる
2024/09/19(木) 15:50:31.78ID:c2v//UgT0
おいおい
そのぶん危険なんだから持ち上げる部分でもないだろ
お前も初級
2024/09/19(木) 17:19:57.71ID:cPR7xA8Z0
ナイフは危険だが有用
不器用者は使わない方が良い
2024/09/19(木) 17:44:18.26ID:8NYyNXbk0
>>244
typedefは新たな型を作るわけじゃない別名を定義するだけから

void foo(char hage[10])

void foo(HAGE_TBL hage)
は同じことだよ
2024/09/19(木) 20:28:27.65ID:c2v//UgT0
>>248
c言語ってとっくの昔から自由にキャストしまくれる言語じゃないの知ってるか?
さぁお前はなんと答える?
2024/09/19(木) 20:47:13.84ID:cPR7xA8Z0
そんなに怖がるなよ
食われるわけじゃないんだから
252デフォルトの名無しさん (アウアウエー Sadf-3vlU)
垢版 |
2024/09/19(木) 21:11:19.13ID:/CBFTgYsa
>>245
悟った人は全部void*
253デフォルトの名無しさん (ワッチョイ ff4c-KlCL)
垢版 |
2024/09/19(木) 21:52:43.48ID:j90utfqH0
文字も数字も全部intでいいやん
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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