C言語なら俺に聞け 161
レス数が1000を超えています。これ以上書き込みはできません。
久々に来たけど、C言語はもう人気が無いんかね・・・ 人気って
C言語で作れなんて非効率的なことする人はそういないのでは?
C言語じゃないとダメな環境を除いて 各分野に適したものがあるならそれを使うに越したことは無い。
C が本当に「適している」と言える分野ってそんなに広くないじゃろ……。
どういう言語が適しているのかよくわからんかちょうどよい言語なければ長い物にまかれることになるわけだけど、
様々な分野でそれぞれのよりよい言語が生まれて「長い物」の価値が薄れるならそれは喜ばしいことだと思う。 プログラムをする人が、コンピュータの基本的な知識が無いまましてしまうから
簡単な記述で出来る言語が登場したからかね?
単純に同じ演算を繰り返して比較すると、C言語は処理速度が一番速いとのこと
データを処理するには適しているかと Cの知識はC++をする時に当然必要になる
CはTIOBE言語ランキングで2位で、C++は4位だ
逆に使えない奴はモグリだろw Cを知り、アセンブラを知って、ハードアーキテクチャが分かる ハードの入り口に立つというだけ
Cより遙かに深い世界の Cの奥地が広いと言うならネットはなお広いではないか。 デジタル3年
アナログ5年
高周波10年
なんて言うね
で、おまえらCはどのくらいでおぼえた?
仕事で使えるレベルになるまでに >>14
高周波は、あの分布定数の立体回路が謎に満ちていましたよね、あれ、どうやって設計するんだろう? この世にはプログラミング言語はPHPとJavascriptしか無いと思ってるエンジニア()がたくさんいるから
Pythonの存在も知ってるけどあれはオシャレな感じがしないしオタクがやるものだと思ってる >>14
蟹飯の本は事前に読んでたけど、半年かかった
周りが旧帝工学系院卒ばっかだったから勉強したわ
おれ、旧帝数学だったからポインタとか分からんかった
でも、今ではわしの方が崇められる
日々「チャラい関数、マクロで被せろ」を軸に頑張っとる int (func) (int n)
みたいに関数に()付けるのって何の意味(機能)ですか? 違う! 関数そのもの
#define func(x) (func)(x)
マクロではない「本物の」funcを呼び出すのに使う int (func) (int n) となると宣言の文脈だからそれも違うだろう。
>>21 その記述だけでは a*b+c を (a*b)+c と書いたのと同じで、少なくともその括弧自体には何の効果もない。
何か意味があると思うなら書いた人に聞くしかない。 いやまあ愚痴なんだけど教科書や入門書ってなんでか知らんけど関数ポインタもったいつけて教えたがらないよね… 素人さんには関数ポインタはむずいだろ
関数のポインタをベクトル化してジャンプテーブル代わりになるんもん
つまりスイッチケースが要らない、言う事 ジャンプテーブル使うのと、switch case と、
どちらが高速でしょうね? >>23
それが上手く行くのは、マクロが再帰呼び出しされないような処理が入ってるからだろ ジャンプテーブルを使うと、変数の引き渡しに手間が掛かる
構造体のポインタを渡すとか、引数を沢山渡すとかグローバル変数を使うとか
なので、switch文にして最適化でテーブルジャンプになるのを確認するのがベストかなと gcc拡張機能のラベルのジャンプテーブルが速かった思い出
あれは規格に取り込むべきだと思う それってどんなのだっけか
関数を配列にぶっこんだの? switch caseを最適化させるとジャンプテーブルになっていることはよくあるね 開発環境の都合で C言語しか選択できず
C++ の virtual に相当する機構をなんとか捏造しようと
構造体に関数のポインタをメンバに持つ
あと qsort のまねっこ
(具体的な比較は外に丸投げして そういう関数がある前提でコードを書く >>31
関数内のラベルをローカル配列の初期化て入れられて
goto labelarray[status];
見たいに飛べるやつ >>28 (func)(x) に対して関数型マクロ func(x) の展開は起こらないよ。 調べてみた
Computed gotoってやつね
int main(void)
{
void *table[] = { &&L1, &&L2 };
goto *table[1];
L1: ;
L2: ;
} 話の流れからして
#define func(arg) hoge(arg)
みたいな関数形式マクロがいた場合、
単に void func(int a){} と書くと void hoge(int a){}に置換されて死ぬ。
回避策で void (func)(int a){} としとけば展開されないよ
ってことじゃないの? 確かに、そういう効果はあるね。
それが必要になる状況は思い浮かばないけども。 関数と同名のマクロがわざわざ定義されてるとしたらなんか事情がありそうだが
#undef func
したほうが早くね #undef の後に undef する前へリカバーできるようにする機構ってコンパイラの環境依存だよね
(リカバーのための仕込み)
#undef func
:
void func()
{
}
:
undefのリカバー (以下 func はマクロ側)
: ひょっとして>>21って
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
みたいな書き方のこと?
この場合はカッコなし int *compar(const void *, const void *)
だとintへのポインタを返す関数の実体ということになり
引数宣言内に関数の実体を書くなと言われてしまうだろう >>26
そうやって教えないでいて唐突になんの前触れもなく使われて「これ何ですか?」って質問したら「関数ポインタも知らねえのかよ」
テック系あるある >>44
いや
int (*compar)(const void);
みたいな単独のやつだよ
てか引数に関数入れるのも教えたがらないよねえ😅
ほんと勿体つけるの大好き 要は関数ポインタ知らなくてバカにされただけのおじさんか
const voidだもんな >>46
それじゃエラーにならない?
具体的にどんな場面で使われてるのかわからんことには説明できないな
混乱する書き方だというのは同意するが ああ、それで「関数」ではなく「関数へのポインタ」が定義できるのか
関数の型をtypedefしてからやったほうがわかりやすくない?
WindowsAPIでは大体そんな形になってるから真似してるけど
宣言
typedef int COMP_FUNC(const void *, const void *);
COMP_FUNC comp_A;
COMP_FUNC comp_B;
COMP_FUNC *comp_func = comp_A;
切り替える時
comp_func = comp_B;
呼び出す時
comp_func(...); typedefがめっちゃ気持ち悪い宣言だな
普通はアスタリスクつけてポインタとしてtypedefするもんだと思うよ
sizeof(COMP_FUNC)がいくつになるのか見当がつかない不気味なオブジェクトだ sizeof は関数型の式に対して適用してはならないと制約されているから
関数だったときの結果は未定義で、常識的に考えればコンパイラはエラー扱いにするべきだと思うんだけど
gcc や clang だと何故かエラーにならず 1 を返すんだよな。
(警告は出るけど。)
検出が難しいはずもない (実際に警告は出せてるわけだし) のになんでこうなってんだろ。
1 でなんか便利なことある? まあ、入門書は比較的難しいことを書かないほうが売れそうだけどな
でもそれを勿体つけるというのは違うかと >>50
WINAPIの書き方はこうじゃない?
typedef int (WINAPI *COMP_FUNC)(const void *, const void *);
int WINAPI comp_A(const void *, const void *);
COMP_FUNC comp_func = comp_A; >>51
C++だとポインタじゃない方は関数メンバの宣言にも使えて便利だったりする。 >>54
ポイントされた関数の呼び出しで
comp_func(ptr1, ptr2); も (*comp_func)(ptr1, ptr2); も両方通るのは何でやろね
歴史的な都合? 前者は関数名そのものをポインタとして使い、後者はポインタを明示的に指定することで関数ポインタとして扱う >>50
定義は?
COMP_FUNC comp_A
{
//ここどうやって書くんだ
} >>58
残念ながら定義には関数型 typedef は使えない。
先に typedef を使った宣言だけ書いとけば定義の不整合を検出することはできるようになる。 COMP_FUNC comp_A;
COMP_FUNC comp_B;
こう書かれても仮引数や返却値の型が見えないので
可読性を落としているな >>56
* をいくつ付けても通るのは有名なネタだな。
#include <stdio.h>
int main(void) {
(**********printf)("hello, world\n");
}
関数指示子 (結果が関数型であるような式) は sizeof や & の
オペランドであるときを除いて関数ポインタに (暗黙に) 型変換されるという規則があって、
普通に printf("hello, world\n"); とか書いてあるときでもこの printf は関数ポインタに変換されてる。
関数呼出しは関数に対してではなく関数ポインタに対して行われる。
関数ポインタに * を付けると関数指示子になるけどそれもやっぱり関数ポインタに変換されるので
* をいくつつけても結果は関数ポインタという変なことになる。 そもそもポインタに代入するときも
int a(int b)
{
return b + 1;
}
int (*f)(int) = &a;
じゃなくて
int (*f)(int) = a;
で通るからな >>57
comp_func は 関数のポインタとして宣言されてる変数っすよ
まぁ >>62 だということで納得 余談だが >>62 はあくまでも C の場合の話で、
C++ では名前解決の話が合わさって複雑になってる。
関数呼出しのときに関数名を括弧で囲むかどうかで結果が変わってしまう場合がある。
https://wandbox.org/permlink/MO8NWeVmjoLTLly6
C のコードを C++ に持っていくことはそれなりにあることなので
変な書き方をしてると組み合わせの妙で引っかかることもあるかもね。 正直どうでもいい
遠い昔Z80のニモニックでJP (HL)と書くけど本来はJP HLとなるはずじゃないかなと思ってたけどそれと同じw Cで関数のポインタガーとかやってる暇あったらC#のデレゲートとかラムダとか覚えた方がいいとおもった午後 「min」と「max」の関数形式マクロをわざわざ定義する.hがあるらしい >>67
コンバイラ、甘やかしてはイカン
最初から攻める気持ちが大切 JP (HL)って8080だとPCHLだっけ
アセンブラがとことん楽するようなニモニックだったな… 関数の引数リストの中で新たな構造体を定義するってことってできないの?
void func(struct X{int a;} b){
... something ...
}
みたいに?
構文上は可能だと思うんだけどどうなんですか? >>47
いみもなく勿体つけるオジサン
「関数ポインタは難しいから後でやろうね~オマジナイだよ~」 >>53
それで後々になって質問すると
>>47,48みたいのが湧くでしょ 未だに初っ端からコンソールにハローワールド表示させるとこから教えてるんだろうね勿体つけオジサンたちは 勿体つけオジサンたちはChatGTPで「C言語で関数名に()付けるのって何ですか?」って聞いてみればいいよ
機械以下のゴミw 配列に対してポインタでアクセスするとか、単純な者だと絵に描けば大体理解出来るが
構造体内のポインタ変数やら、さらに配列かして行くと、記述もすんなりとできなくなるし
ましてや別人が書いたソースで、それらが一体何をアクセスしているのか理解するのは大変だ >>76
返り値のほうならなぜかgccでいけた
まあ型推論がないC言語じゃあ役に立たないんだけど
// main.c
struct {int a;} func();
int main(){
printf("%d\n", func());
}
// other.c
int func(){ return 42;} void func(struct {int a;} b){
b.a = 10;
printf("%d\n", b.a);
}
tccでもこれ通るな >>76
私が知る限りにおいて文法上は正しい。
しかし X の有効範囲 (スコープ) は関数内だけなので
関数の外で struct X に対応する値を生成できず、
まともな方法では適切な実引数を与えることができない。
内容が同じ構造体は「適合」するし引数が適合する関数も適合するはずなので
強引にキャストして呼出しても言語仕様に反しないと思うのだけど
適合の概念をちゃんと理解できてる自信はない……
void func(struct X{int a;} b){}
int main(void) {
struct X{int a;} b = {1};
// このキャストはたぶんアリだと思うけど自信はない
void (*f)(struct X) = (void(*)(struct X))func;
f(b);
} >>76
素直に最初に構造体をtypedef しとけば楽だと思うんですが
文法上で言えばstruct Xとだけ書いといて後でstruct Xの中身を定義しても正しい
もちろんそれでは関数スタックのサイズを計算できないのでエラーになるだろうが Cは
struct Hoge {int a;} b;
と
struct {int a;} b;
を区別しない >>88
名前の有無が違うし、変数名を変えて並べれば違う型になるし、明らかに違うと思うんだけど
何をもって「区別しない」なんて言うのか。 >>86
「内容が同じ構造体は「適合」する」について確認すると策定中の C23 から
内容に加えてタグ名まで同じ場合に限り適合する(compatible になる)ように変更されるようで、
現時点では正しくない模様。
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3037.pdf >>90
厳格な方向に改定してんのね。
今までが緩すぎたからしょうがないね。 >>91
あ、ごめん書き方が悪かった。
これまではタグ及び内容が同じでも適合しなかったところ、 C23 から適合するようになるという話。
有効になるプログラムが増えるので、どちらかというと緩くなる変更。 急に凄くレベル低い話して申し訳ないんだけど
#include <stdio.h>
int main()
{
int a[101] = {};
a[0] = 2;
a[1] = 3;
for (int i = 4; i < 1000; i++) {
int r = 1, j;
for (j = 0; j <= 100 && a[j] != 0; j++) {
if ((i % a[j]) == 0) {
r = 0;
break;
}
}
printf("%d %d %d %d %d \n", i, j, a[j], i % a[j], r);
if (r)
a[j + 1] = i;
}
for (int i = 0; i < 100; i++)
printf("%d ", a[i]);
}
なんでこれ上手く動かないんだろう このスレいつもレベル低いから大丈夫でしょ
上手く動かない?そもそもそのコードはどう動いて欲しいのか読み取れないんだよな
日頃から入出力を意識して書けって言われてない?まるで実践できてないからダメか >>93
二つ目の for ループから抜ける条件の一つが「a[j]がゼロ」なのに、そのループから抜けた直後で i % a[j] とかやってて、jが2のときにa[2]が0でループから抜けるから、ゼロ除算で落ちる
それとこっちは直接の原因ではないけど、int a[101]と宣言すると a[0]~a[100]までしかアクセスできないのにa[102]までアクセスする可能性があるようなコードになってるのもダメだな とりあえず初期化するとき
int a[101] = {0,1,2};
と書いたほうが楽じゃん
ちなみに初期値がない部分は0になる
後はめんどくさいから明日読むわ 間違えた
int a[101] = {1,2};
か
ちなみに int a[101] = {};
ではまったく初期化されないからこのプログラムでは[0][1]以外のところには0ではなく不定値が入ってるのでうまく動かないのはそれなんじゃね
int a[101] = {0};
と書いておけば省略した部分もすべての要素が0で初期化されるよ >>93
i と j ってわかりづらいから j は k に置き換えて言うけど
i=4 のとき k=0 で 4%2 となり割り切れるため、何もせずに次
i=5 のとき k=2 で a[k]==0 なので k のループを抜ける(このときk==2でa[2])
抜けた後のif (r) a[k + 1] = i; で a[3] = 5 になっていて a[2] は 0 のまま
で0除算でドボン
まずはif (r) a[k + 1] = i; ではなく if (r) a[k] = i; だね >>93
それとこれって素数を見つけるプログラムと思うけど、 1000までの間に163個あるっぽい
a の要素数はそれ以上必要
(0除算している部分のprintfがデバッグ用のように、デバッグで100までに制限しているのかもしれないけど)
一応言っておくと0除算でドボンは本質とはちょっと違うからね
if (r) a[j] = i;
printf("%d %d %d %d %d \n", i, j, a[j], i % a[j], r);
とa[j] への代入とデバッグ用のprintfの位置を入れ替えれば0除算は起きないから >>95-99
丁寧な解説、ありがとうございます。
>>95,99
printfの中で0で割ってる可能性に気づいてなかったです。
a[k + 1]に代入しておかしくなってたので、原因を突き止めようとしたら
新しいバグを作ってしまっていました。
>>97
私の使ってるコンパイラだとどれでも
int a[101] = {};
でなぜか全部0が入ります。そんなものかと思って通してました。 右辺のない変数宣言だけのパターンでは変わってくるけど
静的だろうが自動だろうが 初期化の = { } は 省略部以降すべて0 → 全部0フィル でしょ 初期化って必ず初期値を設定するものとばかり思ってた 配列を「={};」で初期化したときの挙動は全要素が0埋めされるとC言語規格で決まってる C17 までは初期化子が 0 個の状況は規定されていない。
一個以上が必要。 0 個を許容するとしたら処理系の拡張。
C23 からは >>102 の説明で正しい。 むかしニコ動で動画上げたらそのこと教えてくれた人いたな
今でも覚えてるわ なので 全省略せずに = { 0 }; と書くことは多いね https://ideone.com/Kj806d
うちの環境(tcc)だと
ビット操作の実行時間: 0.634000秒
一時変数の利用の実行時間: 0.444000秒
ポインタの利用の実行時間: 0.471000秒
になるんですね、最適化が弱いにしても完全に想像と逆の結果になって驚いてる CPU の性質も考慮する必要がある。
ビット演算はメモリのロード/ストアとは並列化できない分が効いて遅くなるんじゃないかと思う。
間接参照があればその分だけ遅くなるのも自然だし、想像通りだろ。 gcc(-O2)で見てみたら核の部分はswap_bitsが6命令、swap_tempが4命令になってるね
swap_bits:
.LFB0:
.cfi_startproc
endbr64
cmpq %rsi, %rdi
je .L1
movl (%rdi), %eax
xorl (%rsi), %eax
movl %eax, (%rdi)
xorl (%rsi), %eax
movl %eax, (%rsi)
xorl %eax, (%rdi)
.L1:
ret
.cfi_endproc
swap_temp:
.LFB1:
.cfi_startproc
endbr64
cmpq %rsi, %rdi
je .L4
movl (%rdi), %eax
movl (%rsi), %edx
movl %edx, (%rdi)
movl %eax, (%rsi)
.L4:
ret
.cfi_endproc ビット演算はそりゃ遅いだろ
読んで演算して書く
よりも
読んで書く
のほうが早いに決まってるじゃん ビット演算バージョンの特徴は一時的な格納場所が不要なところにある。
レジスタに空きが無いときにメモリに退避するよりはビット演算のほうが
マシということはありうると思う。
素朴なアーキテクチャだとメモリの読み書きが (レジスタと比べて) だいぶん遅かったり
レジスタの数が少なかったりするし。
色々な条件が絡み合うので「決まってる」とまでは言い切れない。 この件の場合は
関数の形でメモリから読んで書くことは確定だからそれ以上の最適化は不可能なので決まってるのだ 大昔の技術
今使うやつはアホ
ビット演算の方が有意に速い事なんか無いよ std::swap使えばマシン語のxchgを使ってくれそうな気がするけどね
xchg使うのが最速だろう
Cにはstd::swapに相当するもんが無いな >>117
movだけなら演算ポートを使わないで済む
>>118
マシン語のxchgは非常に遅い >>117
初心者が陥りやすい錯覚だな
「何もしない(NOPのことではない)」よりも速い命令はないのだ >>117
やめとけ
言ってわかる相手じゃない
何もかも機械がやってくれるから
自分の頭で考える必要はないって手合いだぞ ×自分の頭で考える必要はない
○アホが工夫すると遅くなる 今では通用しない技術を偉そうに語る
老害の典型
==>はちみつ 身に覚えのあるやつがファビョってるね
ん~いい返事だ >>119
遅いってのは、レジスタを余計に1つ消費する方法よりも更にデメリットが有るぐらい遅いのか? 最適化されてもmovより遅くならない程度で決して速くなることはない
おそらくもっと複雑な処理の途中でレジスタが全て使用中の場合にレジスタをスタック等に退避することなく値を交換するテクニックとして使われたら速くなるのかもしれんが
こんなシンプルなコードでは起きないだろう xorスワップは昔クヌースのメモリを使わないGCのマーク&スイープ手法だかで多用されてた気がする
当時はこれが神が作りしコードかあみたいに感動しかなかった >>126
普通のコードだとレジスタは常に足りてないだろ
ベンチマーク的なコードは本当の速度を表してないな
Benchmarks gameとかそれぐらい複雑なコードを複数動かしてやっと分かるもんだろうね >>125
現代的な CPU だと直接的に使われるレジスタのほかに内部にはもっと多くのレジスタがあって
見かけ上はレジスタを余計に消費していても実際には一時的に割り当てられるレジスタなことがある。
いわるゆる「機械語」も CPU 内部ではさらに分解されてよりよい命令列に置き換えられるので
同じ機械語でも文脈によって違うことをしてる。
複雑すぎて詳細な挙動を事前に予測するのは無理。
xchg が存在するからには有用な場面もあるんだろうとは思うが、
結局のところは実際にやってみないとよくわからん。 変数のswapって、マシン語に限らずどこででも高い頻度で使うぞ >>129
つまり
有用な場面を知らないわけだ
レジスタを節約するためでも微妙な高速化のためでもないから アトミックのことかな
はちみつ氏のレスは慎重で丁寧だし、噛みつく必要はないだろう そもそもアセンブラででも書かない限りある値がレジスタに維持される期間は人間の考えとは異なるんだよなぁ DJNZがatomicだと思っていた時期が私にもありました >>137
おお、読み出すまで値が確定しないレジスタ
乱数発生専用レジスタですね
わかります 異分野からきた地頭のいい人がCも使えるようになると
おまえら仕事取られるぞ 外国人労働者が来たら、AI化されたら、昔から色んな業種で何度も言われてるわな。 >>148
恐れるに足らん
こっちは守護だぞ幕府が後ろ盾だぞ 前回のこのスレの投稿で関数名に()をつける場合があるという意味がわかった。#undefを使わなく
てもいいように関数に()をつける場合がある。
例
ans = (sqr)(n);
という具合に。 void a() __attribute__((naked));
void a()
{
asm(" halt");
}
int main(void)
{
a();
} 文字列処理用のリングバッファ作ったんですが、同じ処理をint型でも行いたいです。
当たり前ですが、同じプログラムをint型に変えればできると思います。
ですが、処理自体は同じなので、共通化できないものでしょうか?
C++ではテンプレート関数を使えばできるようですが、純粋なC言語では難しいですか? >>161
#defineと#includeを使えばできるよ。 もしくは void* と型の大きさにする形で型を消去してしまう (たとえば qsort のように) という選択肢もある。
間違った使い方をしても (型が消えているので) コンパイル時にエラーとして検出しづらくなる可能性があるけど。
まあどちらにしても C でやるのは煩雑。
使う型が二種類だけであることがわかっている状況だと仮定してよいなら
共通化しようとするよりもコピペしたほうがかえって楽というのもよくあること。 勉強目的なので、試してみます。
#defineでやるやり方は何となくわかるのですが、#includeよりtypedefとはどういうことですか?
void*もよくわからないので、こっちはまだ早そうです。 >>165
//fig1
#define ITERATOR int*
ITERATOR enq, deq;
//fig2
typedef int* ITERATOR;
ITERATOR enq, deq;
fig1ではdeqがポインタではなくなってしまうが
fig2ならこうした問題が起こらない あ、言い間違えてんの今気がついたw
- #include
+ #define
すまんこ リストなどのコンテナ実装でデータの実態へはvoid*でポインタ指定すれば何でも格納できる
基本的にこれで汎用化できる リングバッファくらい簡単なのはその都度作ればいいんじゃないと思う
細かく改良していけばスキルアップになるぞ 初心者質問失礼します
scanf_sやfopen_sなどの関数が含まれたソースをgcc 9.4.0でコンパイルすると失敗するのですがこれは仕様でしょうか?
これらの関数はC11で定義されていますが基本的にMSVCでしか使えないという感じでしょうか? やれやれ…初心者質問あるあるだけ回答しておこうか
「失敗する」とは一体をもって判断したのか。そもそも処理系から何かメッセージは出ていなかったのか。初心者と自覚するなら質問に主観は一切不要だからそれを書きなよ >>170
C11 で規定されているけれど仕様としてはオプショナルなもの。
つまり処理系はそれを提供しなくても仕様準拠を名乗れる。
ただし、提供するならばマクロ __STDC_LIB_EXT1__ も定義しておくことになってる。
そんで使うときにはヘッダのインクルード前に __STDC_WANT_LIB_EXT1__ を define しておく必要がある。
MSVC は C11 が発行される前から scanf_s などを提供していた
(というかマイクロソフトがこれらを標準に入れるように働きかけていた)
のでバージョンによっては __STDC_WANT_LIB_EXT1__ を定義するという手順を介さなくても使えるのかもしれない。
私は MSVC を使ってないのでよう知らん。 >>171
失礼しました
gccでコンパイルしたところfopen_sという関数は定義されていないという趣旨のエラーが出た形です
以下詳細になります
環境:WSL2 Ubuntu
コマンド(bash):gcc sample.c -o sample.out
出力:
/home/hoge/Code/sample.c:17:13: warning: implicit declaration of function ‘fopen_s’; did you mean ‘fopen’? [-Wimplicit-function-declaration]
17 | if((error=fopen_s(&fp,filename,"r")) != 0){
| ^~~~~~~
| fopen
/usr/bin/ld: /tmp/ccIXo3dN.o: in function `main':
/home/hoge/Code/sample.c:17: undefined reference to `fopen_s'
collect2: error: ld returned 1 exit status >>172
>>173
ありがとうございます!
アドバイスを参考に以下のように変更しましたが174と同様のエラーが出ます(T_T)
コマンドを以下のように変更
gcc -std=c11 sample.c -o sample.out
ソースファイルの先頭に以下を記述
#define __STDC_WANT_LIB_EXT1__ 1 legacy_stdio_definitions.lib fopen_sって初めて知った
MS社内だけで通じる方言って感じでイヤな感じだな
fopenで書くようにしたほうがいい だいたいwinAPIはファイルを開く時はCreateFile()系を標準にする方針だと思ってたんだが
なんでfopenのパチモノを作るのか理解に苦しむ CreateFile はファイルロックの制御が細かくできたり、ファイルがすでに存在する場合の
処理や、セキュリティなどを考慮した処理など細かい設定ができる。
WindowsではfopenはCreateFileで実装されてるようだ。 >>179
CreateFileなんかで書いたら移植のとき困るだろ
そもそもプラットフォーム気にせず書けるようにCライブラリとして標準化させようとしているんだし
Windowsは移植性を考慮しないならCreateFile系のほうが柔軟に高度なプログラミングが出来るからCreateFile系使えと言っているだけ APIを使うと毎回特権リングを呼び出すから、
小さい読み書きが多いとオーバーヘッドになる
Cランタイムはバッファを使って特権リングの
呼び出しを減らしている >>182
標準化しようとするなら引数や戻り値をfopenに似せるべきだ
これじゃ初心者はわざわざerrnoを受け取る変数を作らなければならないんだなと勘違いするだろ >>184
あくまでCライブラリとして標準化
古い関数に仕様を合わせる必要はないべ
>これじゃ初心者はわざわざerrnoを受け取る変数を作らなければならないんだなと勘違いするだろ
仕様を読まない初心者が悪いと思うんだが 委員長、読まなきゃ使えない関数は捨てられてしまうと思います! じゃあ、使う必要が出てきたら読むことにします
当分、読むことなさそう >>185
必要はある
今回のようにfopen_sをfopenに書き換えようとする(または逆)場合に変なミスを誘発する
大した理由もなく戻り値を変更すべきじゃない(またはfopenの名前を使うべきじゃない) >>168
void*について学習してきました。
キャストしないと使えないようですが、キャストする型の指定はswitch-caseや#ifなどで分岐する感じでしょうか?
それとももっと賢いやり方がありますか? >>190
memcpyなら型が分からなくとも無理やりコピーできる。 void*は元の形がint*でもchar*でもとりあえず何でもありで受け付けるやつ
元の型が何だったかは結局はプログラマ側が保証しとかないといけないので取り扱いは結構危険 >>189
>大した理由もなく戻り値を変更すべきじゃない
関数の戻り値でエラーを返すことでグローバル変数のerrno読み出しタイミングの問題(マルチスレッド対策)に対応したいところって意図だと思うけど違うんかね?
まあ戻り値ではハンドル返してアドレス渡しでエラーを受け取るという方法もあるとは思うけど
>またはfopenの名前を使うべきじゃない
機能としては同じだし俺は別にfopen系の名前のほうが分かりやすくて良いと思う
言いたいことは分かるけどさ、初心者やベテランに関わらずちゃんと仕様を確認するってだけのことじゃね? fprintf_sとかの他の関数がerrnoを返さない以上、
fopen_sでだけerrnoを返しても一貫性がなくて無意味に感じられるんだよな。
結局のところerrno自体をスレッドセーフになるように作るしかなくて、
それで解消したんじゃなかったっけ? >>161 を見てると
コンテナに入れたいのは int な整数なんよな
リングバッファだから 積む側と引っ張り出す側のそれぞれのインターフェースが必要になるけど
void push(int); 実体を受けて内部で malloc してそっちに格納
void pop(int*); malloc された内容を 引数に渡して mallocしたポインタは free しとく
この int の部分が任意の型でよしなにしようとすると
void push(void* , size_t size); 途中送信してもた
void push(const void* , size_t); 実体はポインタで渡す
void pop(void* , size_t);
のように size_t で実体のサイズもらうしかないよね >>193
errno は C11 以降は thread local storage ということになってる。
errno をセットした後に別のスレッドによって内容が書き換えられるということはない。
(やろうとすれば出来なくはないが……。 普通に使ってて間違ってやってしまうということはないだろう。)
C99 でも errno は変更可能な左辺値 (に展開されるマクロ) であることは要求されているが
それが関数呼出しによって得られるものであってもかまわないという記述もあり、
スレッドまわりで問題を起こさないようにする処理はその関数に入れることが出来る。
C99 ではスレッドローカルの概念は提供していないが事実上はスレッドローカル的な
実装に出来るように配慮されてる。
errno が不格好な設計であるのは確かだが、マルチスレッドでは問題にはならない。 >>182
そんなのは fork を先にさっさと実装してから家 >>190
void *hoge は hoge++ 出来ないけど
int *i は i++ 出来るし
double *d も d++ 出来るし
i++ と d++ で足される数も違う
switch case で対応するのはおすすめしない >>198
forkは効率が悪いから必要ない
プロセスは_spawnを使ってスポーンっと産み出すもんだw GetLastErrorみたいにスレッドローカルにすればいいんだよ >>190
そろそろそのやり方自体が賢くないって気づかないかな switchは良くないと思うよ
利用側でそれぞれの型用に別々の関数を書いて使う人が使い分ける感じじゃないかな
それこそ知らんけどレベルで申し訳ないが >>203
毎回関数を作る
だってリングバッファだぞ
目をつぶっていても作れるぞw fread(void *buf, size_t size, size_t n, …
の順もあれば
qsort(void *base, size_t num, size_t size, …
の順もあって
行き当たりばったり感 >>207
じゃあ、ほい
struct CUE{
int size;
int max;
int inp;
int out;
char buf[1];
};
struct CUE *create_cue(int size, int max)
{
struct CUE *cue =malloc(sizeof(struct CUE)+size*max);
if(cue){
cue->size=size;
cue->max=max;
cue->inp=cue->out=0
}
return cue;
}
int cue_get(struct CUE *cue, void*data)
{
if( cue->inp ==cue->out )
return 0;//buffer empty
memcpy(data,&cue->buf[cue->out* cue->size],cue->size);
if(++cue->out>=cue->max) cue->out=0;
return 1;
}
int cue_add(struct CUE *cue, void*newdata)
{
int index = cue->inp;
if(++index>=cue->max) index=0;
if( index ==cue->out ) return 0;//buffer full
memcpy(&cue->buf[cue->inp* cue->size],newdata,cue->size);
cue->inp=index;
return 1;
}
目をつぶって作ったのでバグがあっても知らない
要するにこういうことでしょ
他の人が言ってるように型チェックがまったく働かないので俺は使いたくない memcpyは余計だな。ポインタを返して後は使用者(自分)に委ねるね俺は 重箱の鬼の首をとる応用例
・(Perlを)Pearl って時点でもう程度が知れる
・(Daemon を)Demon って時点でもう程度が知れる ダブルスラッシュがコメントに採用されたのどの版から? >>210
概念的にはgetした瞬間にリングバッファから取り除かれてるはずなので
実際にはバッファが一回りするまで残っているが
消えてるかどうか曖昧で気持ち悪いのでコピーで返したほうが望ましい
まあ好みかもしれんが >>214
MSVC じゃなくて MS-C の 3 くらいからあったかも C99から
それ以前でもコンパイラ拡張で//コメントをサポートしてるのはあるらしいけど
以下のようなエッジケースで解釈が変わる
b=a//**/ 2
;
//コメントを認めないならb=a/2;
//コメントを認めるならb=a; > 目をつぶって作ったのでバグがあっても知らない
そういうのは「作った」とは言わない >>214
C99 からだが経緯としては先に C++ で採用されていたという事情がある。
C with Classes から C++ になる 1984 年頃に BCPL 風を参考にして
スラッシュふたつで始めるコメント記法が導入され、
更に 1998 年にそのコメント記法も含めて ISO の規格として確立した。
C と C++ でプリプロセッサは共用することも多いだろうし
コメントはプリプロセッサで除去するだろうから
C++ で採用された段階で実際には C でもスラッシュふたつのコメント記法を
使えていた環境は割と有ったのだと思う。 マイクロソフトが独自拡張で当時C++のみのはずの//をCでも許していた
言わずと知れた屈指の大手がやっているので規格が追認することとなった 90年後半からしか実務で使ってないけどVCでは普通に書けてたな
UNIX系はベンダー製のCの制限が酷かった思い出 borlandやwatcomでも使えなかったっけか? 便利だからね
オプションで使えなくすることもできたはず int a[3] = {};
int b[3] = {0};
aの初期化はgcc拡張で規格に沿っているのはbの初期化だと記憶していたんだけど、
規格の6.7.8を見るとメンバの個数より波カッコで囲まれた初期化子が少ない場合は暗黙的に静的に初期化するとあった。
この規格の文章を見る限りはaも規格に合致していると思えるんだけど、aがgcc拡張っていうのは本当ですか? 参照した規格はX 3010:2003 (ISO/IEC 9899:1999) です >>228
本当。文法が空の {} を許していない。
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designation(opt) initializer
initializer-list , designation(opt) initializer
C23 から↓で initializer に {} が追加されてようやく通るようになる。
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2900.htm struct hoge {
char a[];
};
struct fuga {
char a[0];
}; >>230
なるほど構文規則ってところを見るんですね
どうもありがとう >>228
gcc でも -pedantic オプションを付けたら警告は出るぞ。
> warning: ISO C forbids empty initializer braces int main(void)って書く流派ってどこでそんなの身に着けたの? >>235
ISO/IEC 9899:2011
5.1.2.2.1 Program startup
1 The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ } >>235
この指摘をしばしば見るが、int main(void) が違反だった時代はいつ頃なの。 C99からint main(void)と書いてもいいらしい main については C89 のときから変わってないよ。 >>237
K&R Cにはvoidというキーワードが存在しなかった K&R第2版にint main(void)なんて書き方出てきた記憶がないんだよね >>241
日本語版だと 41 ページに
「リストが明らかに空であるときには,予約語 void を使うべきである」
と書かれているのを見つけた。 関数定義のときに仮引数がゼロ個なら void を書くのは当然の作法なんだから
main についてはどうでも良いとはいえども main だけ空にするのもなんか変じゃない? 処理系は引数で任意のスタートアップを指定できるからmain書きたくない需要も満たせるよ 初級、めんどくさいので略記
初段、めんどくさいので無注釈
免許皆伝、めんどくさいので無ドキュメント 元々プログラムはまんどくさいを代行するものだし・・・ 組み込みでmainか・・・
ベクタテーブル作るときのラベルがマングリングされてないから短く済むけどそれだけ >>249
main に引数が有るか無いかの話じゃなくて、無いときに void を書くという話題だよ。 実際の組み込み系には、二つのmainエントリーがある
引数のある奴と、無い奴な >>254
組み込みでargcとargvはどんな意味があるってんだ?
コンソールがあるって前提? 意味なんて知るか
ブートローダとか色々都合があるんだよ 環境依存しまくってる部分だとは思うけど
組み込み用のコンパイラでも エントリは main のままなのね 組込みの真のエントリーはresetな
でも普通はそこからmainまではハード会社が提供してる
初期化処理が入るからあんまり触らない リンカにわたすオプションで_startだか_resetだかを指定してるだけ(例えばld -e _start)
自分で初期化を書きたければmakefileに先頭ラベルを記述すればいい 割込みベクタテーブルのリセット割込みのアドレスがエントリポイント
マイコンのリセットでプログラムカウンタのアドレスが設定される K&R Cで「死産だった」とされるentryというキーワードは、多分このへんの話だったんだろうな そもそもCPU(マイコン)と、そのCPUの命令セットに翻訳するコンパイラに自由度を与えるためにC言語規格で明言することを少なめにしてる
0x100からカウンタが始まるだのブートローダーが必要だの環境依存の初期化はコンパイラが知ってれば十分。 コンパイラは知らないよ
スタートアップライブラリが知ってる ああそうかコンパイラ自体は初期化手段知らなくてもいいのね #include <stdio.h>
void stack_size_estimate()
{
int dummy; // スタック上に確保するダミー変数
// スタック上のポインタとダミー変数の差を計算
unsigned long stack_size = (unsigned long)&dummy - (unsigned long)&stack_size_estimate;
printf("Estimated stack size: %lu bytes\n", stack_size);
}
int main()
{
stack_size_estimate();
return 0;
}
Windowsで実行すると毎回結果がばらばらになる アドレス空間レイアウトのランダム化 (ASLR)だろ
差じゃなくてポインターの中身を表示してみればいいじゃん >>267
64bit 版の Windows だとしたら unsigned long はポインタを表すのに十分なサイズではない。
上位バイトが丸ごと抜け落ちて意図した計算が出来てないと思う。
へんなところを引き算するよりベースアドレスを基準に観察したほうがわかりやすいよ。
歴史的事情で Windows ではインスタンスハンドルがベースアドレスそのものということになってる。 そういやlongはWindows環境だと32bitだっけか
size_t使ったほうが面倒がなさそう Windows だとどっちでもいいけど意味の上では uintptr_t のほうが妥当だと思う。 いやもう露骨にbit数書いてくれた方がいいわ
int128とか #include <stdio.h>
#include <Windows.h>
void stack_size_estimate()
{
int dummy; // スタック上に確保するダミー変数
SIZE_T stack_size;
// ダミー変数のアドレスを取得
LPVOID dummy_addr = &dummy;
// メモリ領域の情報を取得
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(dummy_addr, &mbi, sizeof(mbi));
// スタックサイズを計算
stack_size = (SIZE_T)dummy_addr - (SIZE_T)mbi.AllocationBase;
printf("Estimated stack size: %lu bytes\n", stack_size);
}
int main()
{
stack_size_estimate();
return 0;
}
2096444 bytes
になります、予想の5分の1くらいでした >>274
#include <stdint.h> の
int64_tとかじゃあかんの? ここで欲しいのは「ポインタを格納するのに適した整数型」であって
具体的に何ビットなのかをプログラム上で表現するのは筋違いだと思うんだけど
でもまあどうせ処理系に依存するなら抽象を挟んでもあまり得なことも無いかな
とも思うし、まあそこらへんは感覚的なもんやからね……。 >>277
#include <stdint.h>の
intptr_tやuintptr_tじゃあかんの? >>278
いいよ。
私は uintptr_t が妥当と述べてる。 (>>273) Windowsならこうなってるね
LONG_PTR SetWindowLongPtrA(
[in] HWND hWnd,
[in] int nIndex,
[in] LONG_PTR dwNewLong
); それハンドルを取得する関数なのでポインタとはちょっと違う >>275
それで本当にスタックサイズ計算できてるの?
MSの文書だとデフォルトでは1MBと書いてあるし
もし不足が予想されるのならリンクオプションでサイズ変更できるし
本来大きいメモリはalloc系で確保すべき メモリ空間は 64bit あるけどその全てに実メモリが割り当てられているわけでは当然ない。
仮想的なメモリを管理するから API の名前に Virtual とついてて、
AllocationBase は管理している一塊の単位のベースってだけ。
その単位の中の全てがスタック用とは限らないので基準にはならないと思う。
各スレッドのスタックの底は thread information block に格納されているはず。 >>281
違うよ。ポインタと同じサイズの整数値を設定できる関数だよん。
型キャストすればポインタも渡せる。 #include <stdio.h>
void main(void) {
int card[5][5];
int *p;
p = card;
}
gccでコンパイルすると
aa.c:7:11: warning: assignment to ‘int *’ from incompatible pointer type ‘int (*)[5]’ [-Wincompatible-pointer-types]
7 | p = card;
となります。
エラーではないので動くのですが・・・この警告はどうすれば消えますか?
やりたいことは、2次元で宣言してる変数cardを2次元を意識することなくアクセスしたくて*pに代入しています。 >>287
この場合に card の型は int[5][5] なんだけど
配列は配列の先頭要素を指すポインタに暗黙に型変換されるのが基本ルール
だから式中に card が出てきたら int(*)[5] として扱われる。
この型は int* と互換性のない型ということを警告は言ってる。
型が int(*)[5] であるような式に * を付けたら int[5] ということになるんだけど
上述の暗黙の型変換のルールで int* ということになって p の型と一致するようになる。
故に p = *card; で通る。 この場合ってpを長さ25の1次元配列として使っていいという保証あるっけ?
`card[0]`の長さ5の配列と`card[1]`の長さ5の配列に隙間がないことが保証されてればいいんだけど >>291
二次元配列ってのは理屈の上では一次元配列を要素とする配列と解釈される。
一次元配列で要素間に詰め物が入らないなら二次元でも理屈は同じ。 アフォはこう書く
p = (int*)card;
先輩方に見捨てられるので気をつけて >>291
心配なら
int card[5*5];
とでも宣言すれば安心だけど
パディングがもしあるなら card[5];の各要素の間にすでに挟まってるはずなので
card[5][5];も同じようにアクセスできるはず >>291-292
隙間の有無とアクセス保証は関係ないでしょ。少なくとも規格上は。 規格上の規定は要素のレイアウトの規定として私は理解してたので
そのレイアウトと矛盾しなければ一次元の配列として
扱っても仕様に反しないという解釈でいたんだが……。
直接的に書かれている演算方法を経由した場合しか許さん
と捉えたなら保証はないのかもしれない。 解釈の余地があるときは安全側 (制約が厳しい側) で解釈しておくのが筋ではある。 元々配列なんて一次元が基本だし、mallocで確保して多次元配列として扱うなんてのもよくあるし >>299
malloc で確保した領域はどんなオブジェクト (少なくとも仕様の範囲内で作れる型に対応するオブジェクト) に対しても適切に境界調整されている。
そこらへんは別の話。 先頭と領域が確保されていればその間にアクセスできない部分があることはないだろう
そんな器用なことをする必然性がないわ #include <stdio.h>
void main(void) {
int card[5][5];
int **p1;
int *p2
p1 = card;
p2 = card[0];
} >>303
おまえそっちでやれ
○○のはずとかそんなんで書くぐらいなら普通に書け >>301
オブジェクトのレイアウトについての話じゃなくてポインタ演算に制約がある。
ポインタの演算の結果は配列の要素か配列の最後の要素を
ひとつ過ぎた位置を指さなければならない。
その位置にアクセスする (単項演算子 * を適用する) かどうかに関係なく
ポインタの演算の結果がその条件を満たさない場所を指すときは未定義となる。
(C99 なら 6.5.6 の加減演算子の項目に書いてある。)
今回の場合は *card が返すのは二次元配列の「最初の行」を指すポインタなので
このポインタを元に演算した結果が最初の行の外を指してしまったらダメと解釈できる。
仕様に書かれている演算はその演算に相当するレイアウトで配置される
という意味で解釈することも出来ると私は考えていたが
仕様の文面に厳密に言えば駄目かもわからん。
現代的な処理系ではポインタは由来 (provenance) という概念を持っていて
演算の元になったオブジェクトを外れたら未定義であるということを
利用して最適化することもある。
これは実際にある話で、必然性を言うならそれで速くなる可能性があるという理由がある。
仕様に厳密にしないとわけのわからないことが起こるのが C というものなので
仕様の解釈は大事だよ。 >>302
p1 = card; の所はコンパイルエラーが出て欲しいところだが、Cだと警告だけ出して先に進んじゃうかな。 int card[5][5]; となっているとき
&card 二次元配列全体へのポインタ
card 最初の行へのポインタ
*card 最初の要素へのポインタ 2次元配列なんてExcelのRangeオブジェクトが返す配列ぐらいでしかお世話になったことないわ
特に効率的でもないし構造体でええやろ §6.3.2.1の段落2で定める例外にあたらない場合という但し書きが足りないね
悪かったよ 5ch、専用ブラウザがサポート終了し、撤退する様です。
FireFoxだと書き込める様です。
それ以外のブラウザも多分大丈夫なんでしょうが、試してはいません。 処理系が16byte境界に合うように
「card[0][4]とcard[1][0]の間にパディングを入れる」ってのが起こりうるか不安
わざわざコンパイラがそんなことする理由は
1. 16byte境界の合わせたほうがindexの計算が速い
2. card[0][5]へのアクセスを不正とみなして、ここへの書き込みを検知するフラグを入れる
規格上パディングが入らないことが保証されるならこの話は忘れてくれ Talk専用ブラウザ 「Jane Style」 ← 5chの記述が消えました
20230710
Version 5.00 公開
・Talk に対応しました
* 5ch.net のサポートを終了しました
http://janesoft.net/janestyle/ >>314
https://agree.5ch.net/test/read.cgi/operate/9240230711/
正確にはJaneStyleが離反した
> 00015ちゃんねる ★2023/07/11(火) 00:00:00.00ID:LokiTech
> Janestyleはもう5ch.netと提携していません。
> Janestyle以外の専用ブラウザをご利用ください。
> 旧バージョンの5chブラウザ(API前)は近く再度利用可能となります。
> (以下略) >>315
おそらく連続 (contiguously) というのは間に余計なものが入ることはないという意味で書いてると思う。 テスト
> どういう理屈か知らんけど
> chmateで『URLから開く』で見たい板のURL貼り付けして
> 「5ch」の部分を「5Ch」に変えて開くと
> 5chのスレchmateで見れて草
https://twitter.com/motokamin_/status/1678473238177783835
https://twitter.com/5chan_nel (5ch newer account) chmate はもう対応できてないかな。俺は読み書きできるようになったよ。
今これはPCからで Siki っていうの使って書いてるが。 旧 API を復活させて制限が緩くなったから昔の専ブラがそのままかちょっとした設定変更で使えるよ。
今のところ PC 用の専ブラとしては JaneXeno か Siki が決定版だと思われているようだ。 >>321
PCはAPI対応前の昔のlive2ch(live5ch)が使える ninja は make を完全に置き換え可能になったでござるかニンニン? >>324
設計思想が異なる。
ninja は make ほど多機能ではなく、メタビルドツール (cmake など) と組み合わせるのを前提としている。
どうせメタビルドツールは使うという前提なら ninja のほうが使い勝手が良いと思うが、
そうでないなら make のほうが楽だと思う。 現状専用ブラウザJaneStyle4.23を落としてきて修正パッチを当てて動かしてます。
修正パッチは有志が機械語レベルまで降りて解析し対処してます。
今まで無かった機能まで追加してます。その技術力はスゴイですね。
ただ、専用ブラウザは今後5ちゃんねるの仕様が変わったときに
開発者がメンテできるかどうかで生死が決まりそうですね。 なんか昔「コンパイル言語は消滅してスクリプト言語が主流になる!!」って主張聞いて
オープンソースアプリはともかく商業アプリでスクリプト言語使ってたら
速攻解析されてコピーなりクラックされて(その結果どうなるかはわからんけど)商売にならないんじゃないのかと思ったけど
現状どうなのかな?
JaneStyleの 不具合発生→ねらー修正 っての見てるとバイナリーコードでもスクリプトコードでも解析難易度は変わらないのかなとも思うけど。 >>328
事実如何を措いて、
主流以外の傍流は消滅するという理屈がそもそもおかしい。 バイナリクラックなら開発言語そのものにはあまり意味はない気がするけどな
バイナリエディタで稼働中の実行コード覗かれれば元の言語が何であろうが同じこと こういうのはやはりファームやってた人は強いのだろうか?笑 暗号化やら難読化やらを駆使しても
実行中には実行できる形になってるのは
どうしようもないもんな。
だからライセンスで制約を付けるんだが、
不特定多数をユーザーとするビジネスモデルだと
制約を守らせるのも難しいのだと思う。 不具合を何度も指摘されても放置していて
痺れ切らしたユーザーが解析してパッチを公開した
これが最初だったと思う 業務用アプリならサブスクとクラウドって感じだろうけど
個人向けのだとどうなんだろうね
まあそういう海賊版はアップロードした奴を捕まえることで対処しているっぽいけど
アプリの制限取っ払われるのはもうどうしようもないんじゃないかな >>328
次元の違う問題を比較してると思う
スクリプトでコンパイル言語を代替できるようになったとしても
商業ソフトを供給するほうがスクリプトでないと実装できないことにはならないし
サーバーサイドで重要な処理を行うようにすればスクリプトでもそこは解析できないわけだし(今回の5chのAPI仕様変更みたいに) >>328
主流かどうかはわからんけどJavaのような仮想マシンで動くやつは流行ったな(Androidスマホで採用されたので思い切り流行った)。Perlとかのインタープリタの言語も内部でコンパイルしてから動くのでなんとなく似ている。
こういう風に仮想マシンで動くようにするとOSやCPUが違っても互換性を保つのが楽になる。 tiktokなんかjavascriptでVMを実装してその上で独自のコードが動いてるせいで解析が極めて困難になってる /* 文字列を反転させる */
#include <stdio.h>
#include <string.h>
void reverse(char *);
void reverse(char *cp)
{
char *p, *q, wk;
p = cp;
q = &cp[strlen(cp)]-1; // strlen()は'\0'を数えないのに1引かないと正しく動作しない
while (p < q) {
wk = *p;*p = *q;*q = wk;
p++;
q--;
}
}
int main(void)
{
char ss[] = "Program123456789";
reverse(ss);
printf("%s\n", ss);
return 0;
}
上記プログラムでstrlenは'\0'文字をカウントしないのに、1引かないと正しく動作しないのはなぜですか? 343の訂正です
q = &cp[strlen(cp)-1]です 末尾の \0 を入れ替えたらあかんやろ
"AB" は strlen() == 2 になって
0 1 2
[A][B][\0]
こういう配置や strlen は文字数を返す一方で [ ] の中はオフセット量(0スタートの相対距離)だから
1文字目を指すのは オフセット0 の場所なんだわ >>>345 >>>346 即答ありがとうございます
自分はまったく そこまで考えてstlrenを使ってませんでした。ありがとうございます。勉強になります そこまで考えてというか ポインタ/配列添え字 が 0 から始まるだけの話でな
1文字目 = (オフセット)0
2文字目 = (オフセット)1
:
n文字目 = (オフセット)n-1
他所言語(特に古めのBASIC) だと配列の添え字は 1から始まるのが自然だから
その感覚のままだと およよ? ってなる COBOL, PL/I, RPG, FORTRAN, BASIC, R, Lua, Julia は、1で始まる BASIC はバリエーションが多いよ。
0 と 1 を切り替える機能があるやつを知ってる。 >>341
そのやり方だとapple審査通らないのでは? 環境はwebkitでvm自体dlしてくるから問題ないということなのか… >>353
Fortranは添字の開始値を指定しない場合は1から始まり、添字の開始値を指定する場合は任意の整数
(負も可)を指定できるが、Pascalは添字の開始値指定が必須で任意の整数(負も可)を指定できるから、
1から始まるとは言えない。 >>350
ああOPTION BASEかあ
N88BASICの頃からあるが使ってるの見たことない 今時はExcelのセルをCellsでアクセスしたり配列に代入した場合だけ1オリジン固定でちょっと困る
歴史的経緯というよりExcelのCOMオブジェクトの仕様なんだろうけど 配列って
array + sizeof(*array) * index
だから、0からの方が理にかなってると思う
1からの場合は、実行時にアドレスを割り出すときに絶対1引いてるよね…
そこまでしても人間の直感に合わせたかったのだろう 1引いているのはあくまで内部的なもの
それこそ人間の直感に合わせたインターフェイスとコンピュータの都合の良い情報に相互変換するのがプログラムじゃなかろうか
0からのほうが分かりやすいと思うのはプログラマだからだろうし
10個のデータの最後のインデックスは10というのは添え字で考える場合は分かりやすいしね 先頭をゼロと呼ぶか1と呼ぶかならまだマシよ
音楽なんて先頭要素を1と呼ぶだけじゃなく、要素間の差がない事まで、ゼロじゃなく1と呼ぶ
現代人からするとどう考えても頭おかしいが、仕方がない。ゼロの概念がなかった時代から定義が変わらず続いてるらしい Cはゼロに限らず何もないを示すvoidが無い頃は全部intでやってた時代もあるんだよ
頭おかしいな voidが何もないことを示すならvoid*の存在のほうが気になる void だけ特殊な型と考えるしかないのではないかな。大きさが0ビットの型と考えても良いのかも知れないが。 sizeof(void) → 1 だな
これって正式な仕様なのか分からんけど それgccなんかの独自仕様のはず。void*をバイト単位で計算できるから便利なんだけどね。 言語仕様上は void は不完全型とする扱い、かつ sizeof に不完全型を与えることは出来ない。 gccだとsizeof(関数名)も1なんでしょ
明らかにただの手抜き 仕様上の問題は置いておいて
1として扱うと何か良いことあるんでしょうか? 未定義な動作は規格として規格が何ら要求を課さないことを意味するが
但し書きの中に「文書化された環境に特有な方法で処理してもよい」ともある。
GNU C のドキュメントには void と関数 (関数指示子) の大きさについて記述がある。
https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
これも規格が認める正しい動作のひとつ。
それはそうとして処理系に固有の挙動に依存するのを避けるに越したことは無いけど。 >>369
>>365にも書いたけど、演算するのにいちいちchar*などにキャストする必要がない。 void* は演算させないという意思表示なこともあるんで
演算できることが良いわけでもないんだけどね。 どんな用途があるかな?デリファレンス先にアクセスできないってだけで十分な気もするが。 アレじゃないかな?メリットあるとしたら
【struct に含めたメンバーは、サイズゼロはダメ】っていう仕様があったかと思う。
正確には【structの違うメンバーが同じアドレスになったらダメ】だったか
----
以下は蛇足
ただサイズゼロだめってのは例外があって。
structの末尾メンバーでchar[] だか char[0]ってのが、確かC99あたりでアリになった気がする。
これは…それまでも使われてたテクで
【structの最後に char [1] のメンバーを置いて、実際にはメモリ確保の時structのサイズ+可変長部のサイズでメモリ確保し、最後のメンバーを使ってstructのサイズを超えてアクセスする】という慣用句があって、
それの目的で
C言語公式仕様風では char[1] と書き
確か昔は gccだとchar[]
vcだと char[0]
ていう書き方してた。(gccとvcは逆だったかも知れない)
のが、公式仕様でもサイズゼロokになった…という話だったかと。 あ、メリットの言い方をすると
処理系内でstructのサイズ計算を実装するにあたって、あらゆる型がサイズ1以上である事が分かっていれば、合算処理を合理的に実装する事ができる
…よね? 意味不明
メンバーにvoidを含められたとしても参照すればエラーになるはずなので使いようがない
(void*はもともと正しいサイズを持つ)
unionで似たようなことはできる >>375
サイズゼロをOKとすると言ってしまうと語弊があると思う。
仕様上の理屈だと「不完全型を指定できる」だし、そうした場合の動作は
いくつかの特例で成立していて「長さ 0 の配列」は現れない。
sizeof などでは「フレキシブル配列メンバは無視される」だし、
メンバにアクセスするときは
> 置き換えられた配列が要素をもたないとき,それはただ一つの要素をもつのと同じ規則で動作する。
> しかし,その要素にアクセスした場合,又はその要素を一つ越えたポインタを生成した場合,
> その動作は未定義とする。
とあって、長さ 1 として扱うけど要素にはアクセスするなという回りくどい言い回しになってる。 >>375
typedef struct { int x; char a[1]; } A; A *p = (A *)malloc(sizeof(A) - 1 + N);
typedef struct { int y; char b[]; } B; B *q = (B *)malloc(sizeof(B) + N);
typedef struct { int z; char c[0]; } C; C *r = (C *)malloc(sizeof(C) + N);
かな >>378 の主張だと
typedef struct { int y; char b[]; } B; B *q = (B *)malloc(sizeof(B) - 1 + N);
でなければならないのかな >>379
配列の大きさとして 1 を指定して可変長のように扱うやり方については
ちょっと不明瞭なんだが仕様に厳密にいうと準拠してない方法だと考えられている。
https://c-faq.com/struct/structhack.html
配列の大きさが 0 より大きくなければならないということについては
例外を見つけられないのでどこであろうと 0 を指定したら未定義と解釈していいと思う。
GNU C では構造体メンバの最後の配列要素に 0 を指定した場合は
C99 でフレキシブル配列メンバにしたときとほぼ同じような扱いになることがドキュメント化されてる。
https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
つまり GNU C では 0 を指定していいわけだが……結果が同じならあえてやる必要もないな。
GNU C でも構造体の最後の要素を除いて配列の大きさに 0 を指定するのは (可能だが) 推奨されていない。
アクセスした結果は未定義なのでなんの役に立つのかようわからん。 >>380
-1する必要ないな
1バイト程度なら余計に取っても害はない >>382
そういういい加減な見積もりは感心しないな
それに、この場合は-sizeof(int) が正解だと思う >>382-383
どっちも間違い。 この場合は -1 をしてはいけない。 >>383
いい加減なのではなく無駄なことに神経を使わないのがプログラマの秘訣だ
それに他人が見て「この-1はなんだろう?」と無駄な思考時間を取られる可能性を考えたら百害あって一利なしだ
>>384
よく見たらデタラメだな
すまん >>385
1バイトごときのために余計なことをしないってのは理解できる理屈だが、不必要な1バイトを確保するってのもそれはそれで無駄に考えさせられてしまう感じがする。
やろうとしていることと合致しないコードなわけだから。
害はないが役に立ってもいないということを確信するのはどういう役に立っているのかを見つけるより難しい。 >>384
ああ、[1]の場合のコード見てたわ、お恥ずかしい。
どっちにしろ[1]の場合もoffsetofかalignof使ってあれこれだね…sizeofじゃ正解ではない… >>386
どうせmallocは1バイト単位では確保しないので正確なサイズを指定しても構造体一個につき数バイト以上の無駄な領域が確保されることになるし…
この構造体を数万個単位で使うような大規模プログラムで極力ムダを避けたいならmallocは使わず最初に大きなリニア領域を確保してそこから切り分けたほうがいいだろう
蛇足だが経験上こういう構造体を使うときはcopy=malloc(sizeof(A) + strlen(src)); strcpy(copy->a,src);のように使うことが多い
これなら正確なサイズ指定になる
>>387
どっちにしろ君は何か勘違いしてないかな
長ったらしく書くなら-sizeof(int)ではなく-sizeof(char)となる どんどん蛇足的になってしまってる気はするが
1バイトの加減算ってのはインクリ・デクリの1命令で演算できるし分岐しないし、
アライメント境界を1バイト超えたらバス幅分-1の無駄ができるかもなので
しかも100万個の「3d座標型」とかがその理屈で1個につき7バイト無駄にしたら700万バイトが無駄になるので
たかが1バイトと軽視して良いか否かは、状況によります
で、はちみつさんのちみつな調査に感謝。蛇足で変な事書いて仕事増やしてごめんなさい でも、ワシは(もしそれが有効だと判断したら)公式なC言語仕様上未定義になるとしても、
伝統的にgccとvcが「独自拡張」として許してきた書き方で
書くよ
もちろん責任者の許可は伺うけどね
ダメと言われたらもちろんやらない >>388
ちゃんとサイズ確かめた?そんなに簡単なら[]拡張なんて要らないと思わない? で
時には自分が、あるプロジェクトの最高責任者だったりする訳で
その環境は特定のカスタムgccの特定バージョンを使うしか選択肢がないから無用な心配は意味がなくて
次のプロジェクトではどうせ全部作り直しだったりする >>391
何を確かめればいいのかね
正確に書いてくれないと答えようがないな
後半個人的には「要らない」ね
誰かが拡張したら使わないとイケないという「強迫観念」を持ってないか?
それは不要なものだよ >>393
sizeof(A) != sizeof(int) + sizeof(char) >>394
メンバの配置はきっちりつめるのから
nバイトアラインで飛び飛びにしてるのもあるしね >>395
一番最後のメンバの後ろにパディングが足されるかどうかが焦点になる
足されないならイージーに引き算すりゃいいんだが… >>394
意味はわかったけど
君のコードは可搬性がないわけだね
全部作り直しになるのもうなづける
そんなのやってられないw >>399
初歩的な構造体のパッキングルールを理解していたらどうって事無いはずなのだけども…この程度で可読性とか労力とか、そういうレベルの仕事なら使用禁止で良いんじゃないかな。
あと、何か勘違いしているようだけど、[1]だとややこしいけど出来るねって言ってだけで、使うなら[]だよ。c99標準な訳だし。 「-sizeof(int) が正解」とは言えないよ環境による
パッキングルールを変更できる#pragmaもあるから
それは単なる「思い込み」ということになるな >>399
あなたが「君」って言ってる相手は少なくとも私と私以外の2人以上なので 何か誤解してると思う
ここは匿名掲示板なので、想像した人格じゃなくて内容に反応して欲しい 質問失礼します
Windowsソフトが作りたく基礎を勉強したのですがここからソフトを作る道筋が見えてきません
SDKを用い制作するということまではわかったのですがそれについて解説しているサイトがなく詰まっている状態です
おすすめのサイトや参考書などあればご教示くさだい モダンなフレームワークを使った方が良いが
Windows の基礎的な理念というか考え方をかなり平易に
説明したものということだと↓とかが有名だと思う。
http://www.kumei.ne.jp/c_lang/
ただ、古いので実情に合わない部分はある。
Windows には異なる系統の API があって、
現在では COM をベースにした WinRT がモダン API として
整備されているのでそちらを軸にしても良いかもしれない。 SDK使っての開発は30年位昔のやり方なんではないだろうか >>405
>>406
ありがとうございます
早速進めてみます >>407
基礎しかわからない初心者なものでして、、、 Windows のネイティブなプログラム作りには C というよりは C++ の方がよく使われていたと思うので、C++ も覚えた方が作り易くなるような気がする。 >>407
使えるものは使えば良い
昔の方がシンプル
>>410
MFCやATL/WTLやCOMやQtやwxWidgets使いたいならC++だが
生WindowsAPIとSDKやCOMやOpenGLやtcl/tkとか使うならCで充分
むしろCが標準と言っても良いので勉強用ならC 最初残ろは16ビットアプリだったから、
メモリーモデルやアプリが使用可能なリソースサイズなど
結構管理が大変だった記憶がある 勉強目的の縛りプレイじゃなければ最初からCじゃなくC++使う方が良いと思うが。 いまだにCOM ATL DirectX IDL辺りの定義見るとC知識では手に負えないイメージ
C++MFC全盛の時代は本当に嫌いだった
C#でそれらに一切関わる必要がなくなってほんと良かったわ 古いAPIの設計思想が時代に合わないのも多いし、フレッシュな知識を蓄積したほうがいいという意味ではWinRTかな とりあえず現在でWindowsアプリのプログラミングを始めるにあたり、C言語というのはやめるべき
悪いこと言わないからせめてC++にしておけ
そして楽に作りたいならC#にしておけ C でやってみれば (やれるだけの知識を身に付ければ) 低レイヤで何が起こっているのかという具体的なメカニズムを理解できるという意味で悪くはないと思う。
ただ、今となっては日常的にやるもんではない。 C#で.NETにない事をやろうとするとpnvoke知識が必須だから
Cを適当に摘みつつC#でいいんじゃなかろうか
C++はもう時間の無駄
時間が無限にあるならどうぞ Windowsの動作原理を学びたいなら、SDKやMFCは良いと思うよ 今のWindowsの最新のUIは全てWinRTの上に構築されている
Githubでソース見れば一目瞭然
完全に今のWindowsの基礎となるAPI
無知というのは罪だな まさかWinRTでマウント取ろうとする馬鹿が居ると思わないわ >>427
無知乙w
正論にキレるの図w
反応しなきゃいいのにw mallocの戻り値は代入先のポインタ型にキャストして使おうと言ってる入門サイトがほとんどです。
これは正しくなくて、キャスト不要が正しいと思いますが達人の皆さんの意見はどうですか。 C++ならvoid*からのキャスト必須。C言語ならキャスト不要。 >>431
害悪はオマエだろ!
WinRTが終わったAPIみたいなフェイクを正したんだよ!
WinUIとかGithubでソース公開されてんだから、ソース見れば一目瞭然だろ!
2度とフェイクを書き込むなよ! もしかしてWindowsRT(ARM版Windows8)と勘違いしてたりして WindowsRTは失敗したプロダクトだけど、WinRTは完全にWin32を置き換える為のモダンな基盤APIになった
ちなみにWinRTに関する情報は全然出回ってないな(少なくとも日本では)
MSも直接使うAPIじゃないと考えてるのかもしれない
実際、WinUI3とかを通して使うことになるのだろう MSは一時的に、DirectXやActiveXみたいにRTを流行らそうと考えてたふしがある
でも、まったく浸透せずにRTに悪いイメージだけが残ったw >>432
型変換とキャストを混同して説明していることがそれなりにある。
それとは別に不要でもキャストすべきかどうかというのは習慣の問題。 人にとっての読みやすさは仕様上の要・不用とは別の話なので明瞭な答えはない。 UWPのWinRTでファイルアクセスなどに制約がある場合があって
APIレベルでセキュリティ上の制限があるのかと思ってたが間違いで
他のプラットフォームで呼ぶと普通に色々アクセス出来てしまう そろそろ他所でやってくれんか
普段Windowsには世話になってるけどUWPの存在には憎しみさえ感じる >>441
cast という単語には型変換の意味があると思うが?
で、実際にプログラミング言語では型が変換されるから、型変換で良いんじゃないの? >>444
Cの仕様上の意味合いとしてはキャストという用語は構文 (記法) を指している。
括弧の中に型を書いたやつを式の前に置く、あの構文のことね。
キャストを使わない形でも (暗黙の) 型変換が起こることはあるし、
型を変えないキャストも出来る。 型変換とキャストは同一ではないよ。
カジュアルな場合では文脈でわかるし、ときには同一視してもいいこともあるけど >>442 の文脈では
構文のことを言っているのか型変換のことを言っているのかで事情が変わってくるので
厳密でなくても良いとは言えない。 >>445
アンカーを間違えた。 >>442 じゃなくて >>432 ね。 「毎日出社したい」わずか3.8% リモートワーク経験者に聞いた
学研ホールディングスのグループ会社であるベンド(東京都千代田区)は、リモートワーク
経験者を対象に「リモートワークに関するアンケート」を実施した。その結果、半数近くの
人が「週5(フルリモート)」(44.4%)をリモートワークの理想の頻度だと考えていること
が分かった。
次いで「週3〜4」(30.7%)、「週1〜2」(20.1%)と続き、96.2%の人がリモートワークの
継続を希望していることが分かった。毎日出社を希望する人は、わずか3.8%だった。
出社を希望しない理由は「通勤にかかる時間や体力がもったいない」「子どもの都合で、
リモートワークのほうが仕事と家庭のバランスが取りやすい」「職場の人と毎日顔を合わせる
のはさすがにつらい」といった意見が寄せられた。
一方、「コミュニケーションが取りにくくなる」「出社しないとできない業務がある」
「たまには出社もいい気分転換になる」など、完全リモートだと不都合だという声もあった。 >>445
冗長 int *p = (int *)malloc(400);
簡潔 int *p = malloc(400);
ということを言うつもりで書きました。 >>448
仕様上は暗黙の型変換が適用される場面。
キャストを書かなくても型変換はされることが保証される。
ただ、 >>434 で言及されているように C++ ではキャスト必須なのでそれに合わせる (ことで C++ としてもコンパイルできるようにする) ほうが好ましいという考え方もある。 これが暗黙に変換できてしまうのは良い仕様とは言えないのは確かだからより厳しいルールの C++ に合わせるのも一応の合理性はある。
誤解の余地もない (と思う) ので私はキャストを書かない派なのだけど、以前にツイッターかどこかのアンケートで見た感じでは拮抗してて、どちらが優勢というわけでもなかった。 int *p = (int *)malloc(400);
冗長ではないよ C++でnewではなくmallocをあえて使う理由って何かあるのかな? >>449
くわしくありがとう。そういう見方もあるのですね。
アンケートで拮抗というのはわかる気がしていて、その理由が入門書やサイトにあるのではと思うのです。
>>450はなぜそう思いますか。 void *が無かった頃はmallocもintやchar *を返していた時代がある
処理系渡り歩いてきた老害ほどmallocでキャストしたがるだけだろ
大した話でも何でもない >>454
可読性が上がるだろうか? 少なくとも >>448 のように変数の型がその行に書いてあるようなケースでは
誤読の余地は全然ないように見えるので同じ情報を重複して書く意味が感じられない。 >>448
組織(会社とか)のコードだと、どんな水準の人がメンテするか分からないので、冗長を採るかな。
> 冗長 int *p = (int *)malloc(400); この話が一番冗長だtoomou
kanjidenakunatta >>452
K&R の第二版 (日本語版) でもキャストは必要だと書かれているんだよなあ……。
本の最後に仕様をまとめているところでは暗黙に変換されることも言及されているのでおそらく改定漏れなだけなんだろうけど。
かなり長く定番の入門書だったのでこの本の影響も大きいと思う。 暗黙に変換って、プログラム書いてる本人の意図通りなら良いんだけど
意図と違った変換するとやっかいだな 昔のmalloc()ってchar*とか返してた気がするな
最初っからvoid*って有ったのだろうか? すべての戻り値はintである
ポインタかどうかは書いた人間がが判断する >>464
AIが混乱するようなことを言わないでほしいも >>464
それ LLP64 でも同じこと言えるの? >>464
それはB言語のようなミニ言語やBLISSやアセンブラのようなシステム記述言語でよくあるやつだな。
そういう血塗られたルーツを持つCが普及してしまったのがこの大災害の原因ではあるが。 ポインタじゃない構造体の代入はメモリコピーで、intじゃないよね >>467
それですよ。
あと、実際の案件で
メモリバスが32より大きい環境でも、64ビット全部が使われてるとは限らないです。
あるビットにこう入ってたら40ビットのxxメモリ空間を指し、あるビットにこう入ってたら48ビットのyy空間を指す、とか
ポインタ値にも複数の種類がある(ように設計する事がある)
何が言いたいかというと全部intだなんてのは、分かってない証拠 昔は関数から戻り値として構造体が返せなかった
MSか勝手に実装した 返せなくても困らなかったけど
例えばポインタで返しているAPIはいくつかあるだろうし
呼出時に渡す構造体で返すやり方も普通にある(こちらの方が多いかも) 8051風のMCUにはメモリ空間が複数種類あるものがあって、どのメモリ空間をポイントするかによってポインタのサイズが1byteか2byteかに分かれるというのがありました。 >>473
K&R の初版 (1978 年) の段階では
構造体を関数の返却値に出来る仕様ではなかったのは確かだが
その制限は将来的に削除されるとも書いてある。
構造体を返せるようにするのは設計者の計画の内だ。
最初に実装したのが誰なのかは知らんが「勝手に」とは言えないだろう。 えてして実装が先で、規格になるのは後
というのはよくある話 規格が先行することなんて無いでしょ
出来レースみたいな例外を除けば 仕様もクソもANSI Cが出来るまでCに仕様だの規格だの自体がなかったよ
K&Rにしても当時はあくまで標準って位置づけだったし、各処理系で互換性のない部分が結構ある時代だった
そもそもK&Rって本自体Cの言語としての仕様を示すための本じゃなくて、Cの使い方を説明するユーザーガイド的な書籍だしな
大体、当のデニスリッチーからしてK&R初版の時点で自分のコンパイラではすでに構造体のやりとりを実装させてたんだから K&Rはバイブルってだけ
宗教に喩えて開祖だか教祖だかが著したもの >>481
天国が来るだろう(構造体の戻り値)って書いてあるんだから天国の到来を疑ってはいかんだろw なーおまえ、c言語ちゅーもんはそんなに甘いもんやおまへんのや。もっと真面目にやれー >>480
そういう感じでバイブルと呼ばれる本がいくつかあって、暫くしたら本のタイトルにバイブルって入ってるやつが出てきてアホかと思った事がある。
まあ、本のタイトルは出版社側がなんとなく売れそうな感じのものを考えて付ける事が多いらしいので仕方がない事なのかも知れないが。 >>487
レコードの回転数変えるように。
などと書いて話が通じる人は年寄り。 LP 33+1/3 回転を更に Long Play 化したのが LLP64 なの? 回転数が速いと情報量が増える
要するに音質が良くなるんだろ >>492
いまどきのレコードプレイヤーはレーザーで読み取るタイプのもあるんやが
音質や使い勝手よりも針を落とす感覚が好きな懐古趣味の人も
少なからずいそうやなと思う。 そのうち量子センサーなんてでてきて、
盤面を一瞬で読み取って再生する何て出てくるかもね
知らんけど 盤面を写真撮影して凹凸を一度に全部読み、後は再生するだけ。なんてのはできそうだな。 >>498
盤面をスマホで読み取らせて、それを再生してると思わせといて、実はラベルを解析して事前に録音済みのデータを再生するという、イカサマサービスを思い付いたw >>499
OCRプログラムでラベルの写真のタイトル部分の文字列読ませれば可能だが、問題は、ラベルに似せたものの上に書いた文字でも同じように読んで成功してしまうことだ。つまりレコード不要。 そういえばオープンリールも速度とトラック数にこだわりがあったな >>501
さすがにレコードか位は判別可能なんで、そういう誤魔化しは除外できるでしょ
つうか、インチキなんだからどうでもいいんだけどねw 人間「このレコードかけて」
AIスピーカー「かしこまりました…あーあーはってしーないー」
人間「お前が歌うんかい!」 >>499
ワロタ
…でも「顧客が本当に必要なもの」はそれかもしれない 曲を再生して、それをスマホに聴かせ、曲名やアルバム名を調べる
というのは割と使ってる localtimeでtm型のポインタが返ってきますが
これはfreeのような後始末はしなくても良かったんでしたっけ?
以下のt1の後始末です
#include <time.h>
#include <stdio.h>
int main () {
time_t t0 = time (NULL);
struct tm *t1 = localtime (&t0);
return 0;
} 不要
静的な領域なんで
その代わりスレッドセーフじゃないし
次に呼び出したら値が変わっちゃうのでそのまま使うならコピー必須 時間系関数の一部では同じ型のポインタを返す他の関数が
内容を書き換えることもあるということにも気を付ける必要がある。
つまり localtime が返したポインタが指す先は
gmtime の呼び出しで内容が変わるかもしれないし変わらないかもしれない。 >>508,509
あざーす!
思い出しました! そうでした Cの標準ライブラリはメモリ操作関係やsprintfみたいな書式出力系以外は古臭くてほぼ使い物にならないから
システムのAPIを直接呼んだ方がいいよ
ガハハ >>511
えー、お名前教えて
あなたとあなたのコードが関係するプロジェクトは全部避けたいですw >>511
以前に以下のように書いてるところを
using boost::posix_time;
using std;
cout << to_simple_string (second_clock::local_time ()) << '\n';
C++にchronoが入ったので標準ではどう書けば良いのか調べてまして
以下の例を見つけそこでstd::localtime使ってるので聞きました
https://cpprefjp.github.io/reference/chrono/time_point.html
std::system_clock::time_pointってstd::ostreamに直接出力できないんですかね?
すれ違いかもしれんですが 同じ出力になる以下を使用することにします
$ cat test.cpp
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <chrono>
#include <ctime>
#include <iomanip>
int main () {
std::cout << boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time ()) << '\n';
std::chrono::system_clock::time_point p {std::chrono::system_clock::now ()};
std::time_t t {std::chrono::system_clock::to_time_t (p)};
std::tm lt; localtime_r (&t, <);
std::cout << std::put_time (<, "%Y-%b-%d %H:%M:%S\n");
return 0;
}
$ g++ test.cpp
$ ./a.out
2023-Aug-23 15:35:01
2023-Aug-23 15:35:01 >>512
Win32使ってCでコーディングするなら、Win32以外のAPIを呼び出す必要がないな 標準入出力関数を Win32APIだけで実装しなおすのはなかなか
車輪の再発明くさい案件になるな 残念ながらC標準ライブラリは古くて当たり前なんだ…
それを基準にして多くの人が回ってるから変えられないんだろう
でも人間の使える時間は限られてるので使えるものはうまく使ったほうがいい
メンテナンス性は知らないが 新しく作り直したのに使い物にならないのがWIN32APIの凄いところなんだよなw >>515
Win32?今の話の流れと全然関係ないです
私はLinux上で開発してるけど、それも関係ない
いいからお名前教えて まあいいや。どうせ永遠に話通じないし、意味ないね、スレ汚しごめん> all
世界中のあらゆる人と意思疎通できる訳がない >>515
あなたもごめんね、信念に従ってそのまま生きて下さい 何でWinで開発する人って標準ライブラリを毛嫌いしてるんですか? システムコールとか呼んでなかったか?
たしか、目標をセンターに入れてスイッチ、だった Win32とかゲーム開発する時は必須だろ
デバッグ中はprintf使ったりするけど、最終的にはバイナリに標準ライブラリのコードは含めない GNUみたいにそれなりの人たちがディスカッションして作ったものではなく
いかにもマイクロソフトのサラリーマンプログラマたちが適当に会議して作った仕様に見えるので信仰の対象にしてるのは気がしれんw >>523
Win16でmallocなんか使ってたらころされてしまいますよ 16ビットで十分なハンドル値をnearポインタにキャストするというのはいいアイデアだった あぁなるほど!
16bitの頃のMSの貧弱な開発環境で育ったせいで
標準Cに対しては屈折した気持ちのままなのねw 標準ライブラリは古いつーか実環境を考慮してないだけでbit数はあまり関係ない…
理解してないのに無理に話に入ってこんでもいいぞ >>526
いや、初期のマイクロソフト知らないのかよw
闘うプログラマーとか読んでみろ
めちゃくちゃおもろいよ
そんなことも知らないとか、モグリも大概にしろ macOS(iOS)のアプリ作る時は、OPENSTEP由来のFoundationフレームワークを使うだろ
こうなるとprintfも使わずにNSLogばっかりだなw そもそもC言語で新規開発すること自体がほとんどないので標準ライブラリ使うかどうかは今となってはどうでも良い。 macOS以前のmacのCはもっとひどかった黒歴史 >>532
その手の本を本気にするなよ恥ずかしいw
小説だぞ >>536
それで煽ってるつもりかよw
知らないなら黙ってろよ 闘うプログラマーをディスる奴が居るとはな
さすがモグリは違うw お前の聖書を貶されて怒るのはわかるが
ただの宗教を他人におしつけるなw 「綺麗なのは使われてないものだけ」みたいな格言をどっかで見た。 闘うプログラマー懐かしいな
随分と前に上下巻の頃に読んだ
うろ覚えで申し訳ないがwinodwsのAPIセットを考えるのにカトラーと幹部がクルーザーを1~2週間借りて
湖でクルージングしながらゆっくり考えたってところが印象的
クリエイターって感じで良かった 残りの人生がどれだけあるか知らないけどそういう環境でそういう仕事してみたいなと思う C言語の開発って、
ジャングルの中、誰からも支援を受けずに
自給自足で生き残って敵に勝つイメージがあるな
必要な道具は自分で作るみたいな
恵まれた環境で使うには難しい世の中になってきた 闘うプログラマー読んだことないモグリだけど
カトラーがDECから来る前からWindows APIはあったよね? Windowsは1.0からあるからなあw
闘うプログラマーはNTの開発物語
カトラーが関与したのはWindowsNTのAPIセット カトラーが実装したのはカーネルレベルのAPIでしょ
Win32はその上にある win32はもともとWindows NTの機能だよ
それにカーネルだけ実装してWindows NTを発売したとは思えないけど
3.1とかはwin16
ついでNTでwin32
そのあと95が出てくる あの頃はネット接続も一般的ではなかったから Win32s は雑誌の付録とかの形でよく入ってたのを覚えてる。
俺はテックウィンの付録CDから入れたわ。 >>533
macOS(Mac OS X)になって、旧Mac OS由来のCarbon APIのサポートのため
Foundationの下にCoreFoundationというCの共通ライブラリが作られたよね
すなわちC言語が基礎と。おそらく今でも
Carbon亡き今、CoreFoundationを直接使う必要はほぼないけど
書式出力は文字列のクラス(NSString/CFString)に含まれるというべきかな
NSLogも書式出力を受け付けるが、元々ログ出力関数なので Cの規格書の 7.15.1.1 va̲arg には以下の記述があります。
次の実引数が実際にはない場合,又は型が実際の(既定の実引数拡張に従って拡張された)次の実引数の型と適合しない場合,次に掲げる二つの場合を除いて,その動作は,未定義とする。
− 一方の型が符号付き整数型であり,もう一方の型が対応する符号無し整数型であり,
そしてその値が,両方の型で表現可能な値である場合。
− 一方の型がvoid型へのポインタであり,もう一方の型が文字型へのポインタである場合。
これは例えば、可変長引数をとる関数にNULLポインタを渡し、呼び出された側で
FILE *fp = va_arg(ap, FILE *);
として受け取ってはいけない、という事を指すのだと理解しています。
なぜこのような規定が設けられたのでしょう? >>551
実引数と適合しない型で取り出す場合の組み合わせは無数にあり、
多くは無意味でそのすべてについて結果を規定するのは大変だし必要無いので
最低限必要と思われる範囲で動作が規定されている、と考えれば自然。 >>551
そこで規格がしてるのは特定の事柄を想定した話じゃなくて、単に責任の所在について言及してるだけだよ
va_argで指定する型と実引数の型を合わせるのはユーザーの仕事だ、合わない場合は動作を未定義にするよってこと
C FAQ 11.34を参照のこと
また、2つの例外事項はその部分はコンパイラ側が推測して補正出来る事項なのでそこは許容するよってこと >>551
NULLポインターはFILE*と適合(compatible)してるから問題ない
そこに書いてあるのは適合しない場合の事 多数の回答ありがとうございます。
おおむね、先に挙げた例に対しては「問題ない。規格に適合している」とのご意見のようです。
しかし、先に挙げた問題を解決することを目的(の1つ)として、C23では新たに nullptr 定数が設けられる、とも聞いています。
実はそもそも「そんな問題などなかった」という事なのでしょうか? 「逆に」とか「実は」とか中二病は好きだよね
その規格書の文章が判りやすいとも思えないから好きに解釈していいよ >>554 >>555
私の解釈では規格に沿っているとは言えないと思う。
C では整数定数としての 0 は特別な地位にあって空ポインタの定数としても使えるので
#define NULL 0
といった定義でも言語仕様を満たすし実際にこういう定義になっていることも多いのだけれど
状況によっては単に整数と解釈されてしまうことが問題になる。
可変長引数で FILE* を期待しているところに空ポインタを渡すのは許されるが
NULL と書くと (それ単体では整数型なこともあるので) ポインタとは適合しないことがあり得る。
仕様に厳密に言えばその場合の実引数は (void*)0 とか (void*)NULL とか書かないといけない。
大抵の処理系では問題にならないように上手いこと調整されている。
#define NULL 0LL
みたいな感じで (その処理系における) ポインタと同じサイズの整数で定義しておけば一般的な ABI では大丈夫。
(だが言語仕様で保証しているわけではない。)
NULL は整数とポインタを兼ねる (ような定義でも許される) というのが
歴史的経緯によるあまりにもグダグダな場当たり的な規則なので常識的に考えてあかんやろという話。 >>555
>として受け取ってはいけない、という事を指すのだと理解しています。
君のこの理解が間違っていた
それだけでしょ >>554,555
可変長引数として渡したオブジェクトポインタは実引数拡張により全部 void* になるから、
typedef void FILE; とでもなっていない限りは適合するとは言えないよ。
va_arg(ap, FILE *) として受け取ってはいけない(移植性を損ねる)ということで合ってる。
そもそも適合は型と型の関係だから「NULLポインターはFILE*と適合」はおかしい。 >>558
処理系によってはNULLが (void *)0 でなく、
0 と定義されているかもしれない(から駄目)という事ですね。
納得しました。ありがとうございました。 >>560
よく確認してみたら確かにそうだわ……。
NULL が整数として解釈される可能性を考えるまでもなく
void* と FILE* は適合しないな。
ポインタが適合する条件としては同一の修飾がされていることに加えて
両者が適合する型のポインタでなければならないことになってる。
void と FILE は適合しないのだから void* と FILE* が適合することもない。 NULLについては納得しましたが、まだ疑問が残っています。
同じポインタ型であっても、保証されているのは、
「一方の型がvoid型へのポインタであり,もう一方の型が文字型へのポインタである場合」
だけとなっています。この制約の意図が不明です。
例えば、可変長引数をとる関数に (void *)NULL を渡し、呼び出された側で
FILE *fp = va_arg(ap, FILE *);
として受け取るのも不適合に思えます。
この場合でも、(例えば)アライメントの問題があり、互換が保証できるのはvoid型へのポインタと文字型へのポインタだけ、といった事なのでしょうか? >>560
適合しない場合ってのは、FILE*とint*とかを言うのだろう
void*とFILE*は適合しないのか?
それとNULLを0なんかに定義してたら、NULLはintとしか適合しなくなる
なのでNULLポインターは((void*)0)と想定している >>563
適合する型なら許されるということに「加えて」
void* と char* の組み合わせの場合でも許されるという
規定になってるのはわかってる?
>>564
ポインタの適合に関するルールは C99 なら 6.7.5.1 に規定があって
void* と FILE* は適合しない。
> それとNULLを0なんかに定義してたら、NULLはintとしか適合しなくなる
> なのでNULLポインターは((void*)0)と想定している
・ 値0をもつ整数定数式又はその定数式を型void *にキャストした式を,空ポインタ定数(null pointer constant) と呼ぶ。 (§6.3.2.3)
・ NULL は,処理系定義の空ポインタ定数に展開する。 (§7.17)
とあり、 NULL が整数的数式の 0 であることは許容される。 >>565
適合する型なら許される、という点は理解しています。
しかし「void* と FILE* は適合しない」のであれば、
>>563 の例も不適合ではないでしょうか?
また、不適合であっても void* と char* の組み合わせ
の場合なら許される理由は何でしょう? >>566
総合的に言って不適合という理解で正しいということになる。
void* と char* は適合の規則からすると適合ではないのだけれど、
その表現や境界調整は等しいことを保証する規則があるので
この場合に適合と同等の扱いをしても問題にならないから、
まあ出来るようにしておけば便利なこともあるんとちゃうんかなぁ。 >>565
ポインターに0の代入は問題ないけど、ここでの話は可変個引数に渡した時の事を言ってるので((void*)0)じゃないと不味いでしょ >>565
6.7.5.1では、FILEとvoidが適合しないといけない旨の記述があるけど、voidというのは普通に比較して適合かどうか判定できる型なのか?
特別なルールが有って然るべきな気がするけどね >>568
不味いけど NULL が 0 のことはあるという話。 何の話をしてたんだかよくわからんようになったので >>551 を読み返してたんだが
規定が設けられた理由が根本的な疑問ということでいいんかな。
当然だが引数を受け取る側の想定と異なるものを渡したら破綻する。
普通の関数ならコンパイル時に受け取る側と渡す側の型の間に不整合が合ったら
コンパイル時に検出できるし、条件に合えば暗黙の変換もするんだけど
可変長引数の場合は実行時にならないとわからないので
調整する必要なく渡せる条件を規定したらそうなったって感じだと思う。
整数は負数が絡まなければ同じ表現だし
void* と char* にも互換性があることも保証されているので
問題にならない。 ポインタ苦いか塩つぱいか
そが上に熱き涙をしたたらせて
コードを書くはいづこの里のならひぞや
「まずい」や「拙い」でなく「不味い」と書かれると、つい... ヌル文字の実体が数値のゼロということから思いついた理屈なのかな?
ポインタはアドレスで、そのアドレスに格納されている値のことではない。 >>571
色々ありがとうございました。
素朴に考えて、呼び元がポインタを渡し、
それを呼び先がポインタとして受け取れば
(それが何型へのポインタであろうとも)
普通に安全そうに見えるのに、何でこんなに厳しいのか?
そう決まった理由が知りたかった為の質問でした。
誰か、そこら辺の事情を知っている人はいないか? と。 >>575
C言語のポインタは単にアドレス
ただし、構造体なら構造体、関数なら関数で、メモリ上に決まった配置をされるので、なんのポインタかわからないと、メモリのアドレスをずっと追いかけることになる。
コンピューターそのものにはデータ型というものは存在しない。 >>575
単純にアラインの問題じゃないの
char型なら1バイト単位だからどんなアドレスでもOKだが
それ以上のサイズの変数へのポインタは他のポインタへ変換できない可能性があるというのがたてまえで >>575
ポインタの表現は、それが指す先の型によって異なることも言語仕様としては許されるはず。
§6.2.5 でポインタの表現や境界調整要求が等しくあるべき条件が規定されていて
それ以外の条件では同じ表現または境界調整要求を持つ必要はないと書かれてる。
まあそんなアーキテクチャがどれくらい存在するのかは知らんけど いやいや、ポインター(アドレス)自体はアライメントされてない所に格納されてるかもしれんけど、中身のアドレス自体は問題ないアライメントになってることが保証されてるでしょ
オマエらは何を言ってるんだ? farポインタみたいにバイト数の違うポインタも混在していたら余計にややこしい問題に・・・ 例えばFILE*とshort*ならアドレスのアライメントが合わない場合があるだろうけど、これはそもそも型が適合しないわけでどうしようもない
でも、今考えたらvoid*はありとあらゆるアドレスを取る可能性が有るから、それに合うのはchar*しかないよ、ということを言いたかったのだろうなと気付いた
でも規格書を見ても、FILE*とvoid*が適合するかどうかはアンドキュメンテッドだなw
現実には((void*)0)とFILE*は完全に適合してるけどね ここにこう書いてあるからには、何か(通常の関数呼び出しでは
問題にならないが)可変長引数特有の問題があり、
それを避けるためにこうしたのだろう、と思った訳です。 >>579
そんな保証はまったくない
例えばmallocの場合戻り値は「あらゆる組み込み型に対応できるようにアラインメントされる」と特に注釈されている
逆に言えばvoid*はどんなポインタにキャストしても安全と思い込みがちだがそんなことはないということ
>>582
通常の呼び出しなら型チェックが働くが可変長呼び出しでは一切働かないという注意だろう
最近のprintfは型チェックされるようになってるけど 「環境による」のは安全ではないんだよ
ここで取り上げられてるのは大元の公式文書なのであらゆる環境について言えることが書いてある マイナーなCPUのことなんか気にしたことがなかったな >>584
現在の文脈では「言語仕様をそう決めた理由」が主題。
だからその前提として言語仕様が保証している範囲がどこまでかを
理解しておく必要があって、そこで見当違いの主張に反論がされている
という話の流れ。 >>586
「可搬性」という概念はCでは大事
マイナーなCPUのみならず将来的に登場する高性能だが制限が多いCPUでも手直しせずに動かせるということもあるかもしれない 必要なら環境依存なことをしやすいのも C の良いところだが
不必要な依存は避けるに越したことはないわな FILE *fp = fopen(...);
void *hoge = (void *)fp;
FILE *fuga = (FILE *)hoge;
みたいなことは禁止されてる? どうしても必要ならやるしかない
ただfopenの戻り値でFILE構造体の安全性が保証されてるのにわざわざvoid*に代入してからFILE*に戻すのは
正統な金なのに闇銀行に預けて再びマネーロンダリングするような変な手間だ void *型って参照する先の変数のサイズが不明なので右辺値になるのは不可能な気がするけどな
キャストは無理でしょ >>590
オブジェクトを指す (つまり関数ポインタではない) ポインタを
void* に変換してから元の型に変換すると
元のオブジェクトと等しいことは保証されている。 >>592
void じゃなくてもいいや
FILE *fp = fopen(...);
char *hoge = (char *)fp;
FILE *fuga = (FILE *)hoge;
みたいなことは禁止されてる? >>592
なんで?
ポインタはメモリ上の一点を指すもので
インクリメントデクリメントが不可能なだけで
キャストは可能
>>594
いったい何が聞きたいんだ?
禁止はされてないよ
ただこれ見たプログラマは皆「バカだなあw」とは言うだろうw 言葉をちゃんと使うとプログラマ意思疎通がよくなるのでは。
「void * が右辺値になるのは無理」って何だよ。ではなく、正常動作はプログラマの責任になる、って言いたかったんじゃないの?
>>590 みたいなコードは、これだけなら疑問に思うだろうが、こういうコードが有効になる事はあるよ。その一例は
「ここで言うFILE* みたいなモノが複数種類あり」
送信側 - 中継機能 - 受信側
のプログラム構造で送受信のペアは複数あり、中継機能には 実際の中身が何なのかは意識させたくない。
----
ポインタの話から外れて恐縮だが、
例としてタグ・レングス・バリュー形式ってのがあって、「中継者は送受信データがTLV形式の連続であることだけは知っていて」「TとLのサイズは一定」「タグの種類が何種類あるかなんて知らなくていい」
----
これにさらにポインタを含むデータ構造を通信可能にするには?って話で、ポインタ型をバッファ内インデックス値に変換して、ポインタが指す中身も通信データに含める、とか、
サブ構造がポインタ持ってたら再帰的に処理する、とか話は続くが
それはいいとして
>>590 みたいなコードは、現実にはあるよ。という話 >>594
オブジェクトを指すポインタは char* (またはその他の文字型をさすポインタ) へ変換することは許されるし文字配列として読んでもよい。 (読んだ結果としてどういうレイアウトになってるかはわからんけど。)
そしてもとの型に型変換したら変換前と等しいことも保証される。 たしかに言い方が悪かったので
>>592
ポインタは元々サイズは無いもので
対象オブジェクトの先頭アドレスの一点だけを指してるから
void*を含むどんなポインタもキャストすれば力づくで代入できる
ただvoid*にはサイズがないのでinc dec(加減演算)をしようとするとエラーになる
>>594
どんなキャストも禁止されてはいないが
プログラマの責任によって成される最後の手段だと思ったほうがいい
見つかりにくいバグの原因になるので
ソースにコメントで理由を明示しておいたほうがいい うーん
まだまだ添削できる余地があるぞ…
ここはまあ無料掲示板だが、仕事では、自分には誤解をされやすい性質がある、と意識しなされ ポインタの宣言は、ポインタの型じゃなくて、ポインタが指しているアドレスの格納値をどう扱うつもりなのかを明示している。
void型のポインタは、ポインタだから、何型のポインタだから、64ビットだったり、32ビットだったりするものではない。 >>603
同じでなければならないという規定はない。
実際に異なる実装が存在するのかどうかは知らんけど。 >>594
void void * 登場前の C は
FILE *fp = fopen(...);
int *hoge = (int *)fp;
FILE *fuga = (FILE *)hoge;
だったんじゃないかな >>605
基本はcharだからchar *hoge = (char *)fp;じゃない
なんならint hoge = (int )fp;でもよかった
ほとんどの場合intとポインタのサイズが同じだった >>607 みたいなのがいるから void が出来たんだよ >>607
ウソはだめだ。
俺が見逃しても、はちみつ先生に定規でケツはたかれるぞ そういえば、むかーしの情報処理試験には言語選択でマシン語ってのがあって、1メモリアドレス値が指すメモリは 8bit 幅ではなく、 16bit だったように記憶してる。
「特殊な環境を想定しやがって…」と思ったナカマいない? 試験用アセンブラはCASLだったっけ?
仮想環境で実在しない環境用言語だって。 >>610
char* はどのポインタからも変換できるし
元の型に変換すれば元のポインタと等しいことは保証される。
好ましいとは言えないが変換自体は問題ない。
void* 登場前には (void* 的なことが必要なら) char* が使われていたのは本当だ。
ポインタから整数へも型変換できることは明記されてる。
その結果は処理系定義だが、出来る環境でやるのが悪いわけじゃない。
char* やら int やらで扱ってたら間違った取り扱いをしやすいので
可能なら避けたほうがよくは有るが、 >>607 が言及した範囲には
明瞭に間違いと言えるものは見つけられない。 アドレス範囲ではなくてデータ長が16ビットだったと思う >>611
C の仕様上の用語では「バイト」が 8bit とは限らない定義になっている。
C の仕様で想定する必要がある程度にはそういう環境もあったのだろうし、
主流ではないにしても特殊というほどの感じでもなかったんちゃうか?
まあ「昔」をいつ頃に想定するかにもよるだろうけど。 >>612
たぶんだけど >>611 が言うのは CASL の前身である CAP-X のことじゃないか?
16bit 単位でアドレスが振られる設計だったはず。 7bitでアルファベットは表せてたしねぇ
文字集合で完結させてた RFC822 実際に1バイトが8ビットじゃないマシンで仕事してた人いる?
経験談を聞いてみたい
つらそう UNIXとか基本9ビットが見え隠れしてる気がする
ファイルのパーミッション---rwxrwxとか
C数値のデフォルトが8進数とか(9ビットなら8進数3ケタでまとまりがいい) 1バイト9bitとか完全に都市伝説だろ…
1ワード(レジスタ)が36bitとかはLispマシーンで使われたりしてたけどね とりあえずDSPなんかはそうでしょ
ワードマシンって言っちゃっていいか知らんけど、演算の速度をあげるためにワード幅を一番使いそうなビット数にして全部ワード単位でアクセスする設計にしてる
マニュアルにアドレス、char幅、int幅全部同じ何々ビットです注意してねみたいなのがご丁寧に書いてあったりするよ >>626
float 幅に全揃え
アドレッシングもその単位なのでどうしても細かい粒度で個別に演算処理したい時はビットシフト併用
とかあったなぁ よく分からんけどDSPの内部レジスタって直接浮動少数点数が扱えるのか
floatは符号1bit + 指数部8bit +仮数部23bitの32bit長だっけ?
ただ浮動少数点数でビットシフトって面倒くさそう 外部とやり取りが多少面倒
ファイルや通信関連
データ列をcharに8bitずつ入れるか
ケチって8bit x2 入れるか
なんかを考える必要がある 昔の大型計算機でcharが64bitのがあったはず 最初のUNIX開発マシン、DECの PDP-7 は18ビットだった C の仕様では正数型の表現にパディングビットの存在を許しているんだけど値の表現に関わらない無意味なビット(特殊なフラグとかに使うのか?)が存在するアーキテクチャも、見たことはないけど C の仕様で想定している以上はたぶんあるんだろうな…… T,o,k(迷惑という方は←をあぼーんしてください。)
更に家族友人にも教えて加えて¥4000×人数をGETできます
https://i.imgur.com/dGH5X8i.jpg >>639
PayPayに変換できるって知らなかった あそこはEUから莫大な賠償金請求されたから、必死なんだろう なあ、いつから子関数内で宣言した自動変数を戻り値に使って親関数で参照してもアクセスエラーにならなくなったんだ?
特に構造体とか アクセスエラーってのが実行時の話なら動作環境教えてくれないとなんとも すんません何を言ってるのか分からん
自動変数のアドレスを返す話?
OSとかコンパイラとか色々わからないと空虚な話になりそう、ってのと(特殊な環境なのでは)
エラーになって欲しいのにならなくて
同僚がアホで困ってて
強制的にエラーにしたいって話? 数年に1回ほぼVC++でほぼCのコード書いてコンパイルしてるけど、
なんか最新版入れる度にデフォのエラー基準厳しくなっていく・・・。
変数定義をgoto(エラー処理)ですっ飛ばからエラーって・・・昔のCみたいに関数先頭に記述を移動する羽目に・・・
警告でいいやん。 構造体で返すにしても、呼出元って用意した変数なり構造体で受け取るんだろう >>644
構造体の変数を戻り値に使うことは結構最初の頃から出来たと思うが、昔のマイコンは遅かったのでなるべく使わないで呼ぶ側で変数作ってそのポインタ渡してそこに値入れてもらうみたいな事してたよ。
なんで遅いのかっていうと、参照などという高度なワザは使ってなくて他のintとかの変数と同様に構造体の内容をコピーしているだけだからだ。 共用体で渡したときは、どのメンバー使ってコピーするの? >>650
処理系によってはポインター渡しになってたはず
自動変数はスタック上に領域確保するので
実体渡しじゃ無いとスタック壊れてるよね? 初期K&Rじゃ構造体returnはなくてポータブルC以降じゃね? 構造体を返却値にするときは、
一般的なパソコンでの呼出し規約 (Windows や System V ABI) では
呼出し側で領域を用意してそのアドレスを暗黙の引数として渡す仕組みになってる。
用意された領域の上に最初から値を直接に構築できることもあるので
そういうときはコピーコストは発生しない。
単純な関数、かつモダンなコンパイラを使ってるときは余計な工夫をする必要はないよ。 参照てか自動変数へのポインタを戻してたってこと?
struct foo * hoge()
{
struct foo body;
retrun &body;
}
これ未定義だからどうとでもなってしまうんじゃなかったかな…
コンパイラが気を利かしてエラーや警告にするのも
そのまま実行コードを生成して想定外の動きをするのも >>656
これでいいだろ
struct Hoge *fuga(struct Hoge *param0, int param1, char *param2){
何かする
return param0;
} >>657 のは、OS側のメモリに対する不正アクセスに引っかかって
エラー発報になるのは少ないんじゃないかな?
(戻りの自動変数のポインタが不正アクセスになる可能性は低い)
構造体の中にさらにポインタをつかってて、ゴミなポインタ値で実体見に行ってやっと上記が発動する
struct foo {
struct foo* next;
int body;
};
こんなので ret->next->body; とやったら *ret の内容がゴミ = ret->next も不定な値
ret->next->body でメモリの不正アクセス ハイコストなのをわかってて実体をそのまま返すことはあった
複素数を取り扱う Complex 構造体で 式の形式にしたくて ね >>661
割り込み想定するなら呼び出し元で器渡しとけって話にしかならんじゃろ >>653
返値用にもスタックが用意されてる
特にサイズが自由に定義できる構造体では戻り値にレジスタは使えんだろう ID:wJrbx3oK0 がどういう環境で愚痴ってるのかはわからんけど
「割り込みハンドラ内でいろいろやるのをCで記述してるんだけど…」とかだったら
極力スタックは少なくしたい って話に行き着くけども
それならなおさら器は呼び出し側で用意すべし になるよなぁ
最悪関数呼び出しのオーバーヘッドも嫌って きもいマクロ関数が並ぶことも 似たような話題が出たことがあるような気がしたので思い返してみると C++ スレの話だったわ。
コピーの省略 (copy elision) が保証される場合がどう実装されているのかという話題で
オブジェクトを構築すべき場所を呼び出し側が暗黙に渡してるから
最初からそこに構築される (のでコピーする必要がない) というのが一般的な実装で、
たぶん C の構造体受け渡しで実績があったから C++ では言語仕様として取り込めたんだな。 >>667
返却値のこと。
コンストラクタの場合は結果的に this でもあるとは言えるけど thisはポインタなので実体を返すとか言う話とは関係ない x86-64のABIでは、16byte未満はレジスタで渡されて、それ以上はメモリコピーが発生する、それだけ PODっていうんだっけ
構造体が値わたしになるやつ
これはC++だったかな?Cはよくわからん レジスタが64bit=8bytes
レジスタが128bit=16bytes
たしかにレジスタで全部返せるな >>672
C++ 的にはクラスが一定の条件を満たすと C の構造体と互換性があるような性質を持つ。
それが POD。
C++ の POD のことも慣例で構造体と呼んでると思うので、
C の構造体 ≒ C++ の POD みたいな感じ。
POD は値渡しがどうこうとは無関係。 >>674
あえてマジレスすると
RISCはレジスタ減らす傾向があるのでそれはない
近年のCPUはキャッシュがバカでかいのでレジスタを大きくする必要はあんまりない Plain Old Data だね。
ちゃんとした英語だと、dの繰り返しを避けて Plain Ol' Data とするらしい
最新のC++はPODっていう呼び名を廃止したんじゃ無かった? >>678
概念は廃止した (性質をスタンダードレイアウトとトリビアルに分割して説明している) けど std::is_pod がまだ有るので
「POD がなくなった」と言えるかどうかはちょっと微妙なところ。 >>674
無限では無いけど VLIW って聞いた事無いのかw❤ >>680
Very Long Instruction Word(超長い命令長)で、レジスタ関係無し レジスターを実メモリーサイズに拡張し、実メモリーを廃止
プログラムはレジスターに直接ロード、
データは必要に応じたサイズを割り当てる
一種のチューリングマシン 昔、ルネサスH8だったと思うが、関数内で大きなconst配列を定義したところ、RAM不足のビルドエラーに。
constならROM領域に割り付けるんじゃないのと思いルネに聞いたところ「言語仕様上static変数はconstの有無によらずRAMに割り付けることになってる…」とかいう回答。
Cの規格では割付領域まで規定してるのですかね。
void func(void){
static const char LARGE_TABLE[1024]={...};
...
} Cコンパイラじゃ無くて、リンカに領域指定するんだけどなぁ 処理系定義も広義には言語仕様と言えなくもないんじゃね。
まあ普通は言わんが…… >>684
K&Rは定数文字列書換出来るよ。
組込に向かないって言われた理由や >>681
メモリをレジスタとして扱う技術が無いなら、無関係だろうな。
マイコンだけがコンピューターのアーキテクチャじゃ無いからね H8のフラッシュは書き込み回数が少ないからじゃないかな
その代わり数MBのDRAMモジュール繋いで実行できたから当時のマイコンにしては組み込みlinuxが乗ったりして富豪プログラミングができた >>684
そんな規定は無い。実装の都合としてもわざわざRAMに置いてうれしいこともなさそう。
「言語仕様上自動変数はconstの有無によらずRAMに割り付ける」ならありそうな話なので
あなたの記憶違いの可能性のほうが高そう。 組込みマイコンでconst変数をROMに割り当てるのはスタートアップルーチンの仕事
main関数呼び出し前に実行する処理なので一旦main関数を呼び出してしまった後はROM領域に変数を割り当てる手段はない 皆さんありがとう。
>>691
当たりでした。よく思い返したらそうでした。
void func(void){
const char LARGE_TABLE[1024]={...};
...
}
最初にこう書いたらRAM領域割付になり、結果staticをつけて対処した、のでありました。
で、>>692 のために自動変数はRAM割付なのですね。 なんか、トンチンカンな話ばかりで笑えるなぁ
ROMに割り付けるはRAMに割り付けるかは
リンカーにどう指示するかによるだけだろ
起動後にROMからRAMにコピーするか
そのままROMに置いとくかはデータの属性によって
リンカーがグループ化してくれたものを
起動時にスタートアップルーチンが転送するだけ 基本的に初期値を持つ変数は元の値はROMにあるから
幾らでも呼び出せるが、普通の手段では呼び出せないだけ
強制的にアドレス指定すれば幾らでも呼べる メモリ空間の変数の割り当てはスタートアップルーチンのコーディングで指定する
当然C言語ではなくマイコンメーカー指定の独自言語
大体はただパラメータを設定していくだけだけど つか、ROM上に変数なんか置かないから、置くのは定数 >>674
まあ、プログラムの高速化的には2048bitSIMDか4096bitSIMDレジスタがあると高速化の観点ではかなり都合が良い。AVX2は256bitだから単純計算すると性能が8倍とか16倍とかになるからね。
産業用だとarmのCPUに2048bit長のsimdレジスタがあった気がする。 >>693
自動変数がRAMに割り付けられるのは、再帰のたびに別アドレスとしなければならない規定があるから。
(逆に static なら同一アドレスとしなければならない。)
>692,696 (たぶん同一人物)は ROM/RAM 割り当てがスタートアップルーチンの仕事というが、
仮にそれが正しいとするとスタートアップルーチンはどこからロードするのかという、
おかしな話が出てくるので誤りと考えられる。
実際ルネサスツールでもリンカで指定するものとなっている。
https://www.renesas.com/jp/ja/document/mat/h8s-h8300-series-cc-compiler-package-ver700-users-manual
> 最適化リンケージエディタでは、入力オブジェクトプログラム内の同一セクションを結合し、
> start オプションによって指定されたアドレスに割り付けます。 スタートアップルーチンは内蔵フラッシュメモリ(かマスクROM)に記録されておりベクターテーブル(スタートアップの一部)にリセット割込みのエントリーアドレスを格納しておく
マイコンの電源ONでリセット割込みが発生するとスタートアップルーチン先頭からプログラムカウンタに沿って実行されメモリ変数やスタック領域、SFRの初期設定を行い最後にCのメイン関数が呼び出される >>704
C の変数は const を付けても (C の用語で言うところの) 定数にはならない。
C++ では異なるし、言語仕様の定義でなく単に事前に与える値くらいのニュアンスで定数という用語を使っている解説とかもあって混乱しやすい用語ではある。 const の変数は値の変更が不可能なので、それを利用してコンパイラが最適化することも出来るというだけで、必ず最適化しなければならないとかROMに割り付けなければならないみたいな決まりはない筈。 RAM2KBの環境ではROMに割り付けてもらわないと非常に困る >>707
ならそうしなさいよ、リンカスクリプトで
という話では? 組込みで定数を扱うならdefine定義でソースに埋め込むのが普通
constはregisterと同じ扱いなので>>706の言うとおり いまどきのROM化環境のC言語にゃsectionで領域グループを指定する命令は無いのけ? セクションの初期化を割り当てというから混乱するんだろう
割り当てはリンク時にもう全部終わってる 静的な変数はリンク時はextern宣言で外部定義しておきスタートアップルーチンでセクション割当てすることでメモリ配置を確定させるのが一般的
リンクリストで自動変数以外のすべての使用変数を漏れなく割当てできているか確認する必要がある 人間様はリンカーにセクション配置アドレスを教えるのが仕事だった時代もありました ハードウェア上のメモリー配置を教えるのは、いまでも人間なんじゃないの? >>715
ワンチップマイコンなら型番から自動で割り当ててくれるよ
まあ、外付けメモリ分は手動だけどな 静的変数と自動変数(スタック領域)の容量の割り当ての最終的な決定は人間の仕事
あまり変数に領域を取りすぎるとスタックの分が無くなる >>714
組み込みでそんな優雅なこと言ってたらバグも直せん 昔のトラブルの癖で1Mバイト以上の領域、配列が必要ならmallocで確保するようにしてる・・・。 それ以前だと本体メモリでも64kBフル積んでるの少なくないか 8086積んでた当時のPCは128程度は積んでたと思うが
64でフルになるのはZ80のような8ビットPCでの話 それ以前のそれに8086を含んでるなら矛盾はしない この場合の「フル」はメモリ空間いっぱいのことなんじゃないの。
バンク切り換えまで含めたらいくらでも拡張の余地はあるけど
malloc でバンクを跨ぐわけにはいかんし。 8086のアドレスバスは20ビットだから、1MB実装できる 勉強と言ってももう40年近く昔の知識だぞ
今どき役に立つことなんかあるか? >>731
すいません、ないです。ただ知的好奇心が非常に満たされます。 レトロコンピュータの資料は探せばいくらでもあるが
面白いところだけ選んで読むというわけにはいかんからな。
読む前にどれが面白いのか判断できるわけもないし、
相互に関連があるので一部の資料だけ見ても意味がわからん。
話題に関連する形で昔の話が出てくるのは
それなりに興味深いということもあるんだろう。 スレ違いだったら申し訳ない
c言語でコンパイルした実行ファイルってosのAPIを使用してなければ別々のosで動かせますか?
cpuアーキは同じ前提です。 CPU同じならセットアップの問題とIO関係のクリア出来てたらそこそこは動くんじゃないか 割とマジで試したいなら
Bochs とか QEMU とかで
OS 無しで動かしてみたら良い >>735
原則としては無理。
実行ファイルをメモリに展開して準備するローダがOSの一部だからOS の上で実行するならOSの機能は呼ばれることになる。
実行ファイルの形式が linuxとかだとelf が標準だけどwindowsではpeで、全く互換性はない。
ただ、複数のOSで動く実行ファイルを作るトリックは存在する。
https://justine.lol/cosmopolitan/index.html >>735
大前提が違ってたな
コンパイルしただけでは実行ファイルは造られない
リンカとローダーを通して初めて実行可能なファイルになる >>735
質問者さんは下記の概要を知ると、参考になるかもです
「組み込み開発でベンダーロックを避けるためにマルチハードにしたい開発チームが、対象ハードごとのgccをビルドして用意する手順」
ややこしいし大変なので、ザッとで十分です
参考までに私が買った本(全部読んだとは言ってない)
「LINUX組み込みシステム」
クレイグ・ホーラボウ
ピアソンエデュケーション PC-98用のDOSアプリをTOWNSやAT互換機のDOSで動かしてはいたなぁ。
BIOSコールや各ハード特有機能を使わないアプリに限定されるけど。 >>743
OSが同じなら動くのが当然
MS-DOSがアレだから普通は動かないけどw MS-DOSのシステムコールって機種によらず共通でしょ NHKでタマにやってる「我が社の黒歴史」で
FM-TOWNSを取り上げて欲しいな TownsOSはMacOSみたいなGUIを提供してたんだよな
今やWindows到来って時代にだ TownsOSはMS-DOSを拡張したものだし、
チャレンジ精神を評価する事はあっても
黒歴史とするのはあんまりだ 「我が社の黒歴史」ってやるなら、
是非NHK自身をネタにしてください
ライブドア事件の時、
ニュースに飛びついたNHK社員が
一斉にインサイダー取引で株売買してました
家族にも教えてたそうです
弁護士による内部調査を実施しましたが
社員の多くが調査拒否してましたよ
どんだけ暇なんだろうって思いました あの番組は、黒歴史があるから今の発展がある
みたいなノリの番組だから、後がない企業は扱わないよw TownsOSのこと言うならWin3.1も大して変わらないと思う
どちらもMS-DOSの上で動くGUIシェルの中のひとつ 当時のTownsは386採用し、MS-DOSを拡張して32ビットアクセスを実装してました
DOSが64Kの壁を越えられない時代にギガ単位のメモリをリニアに使える環境を実現
これを使ったゲームが人気でしたね
今から見れば当たり前のことで、何それって時代になってしまいましたが
DOS上のゲームでもこの方式を独自に採用したのがありました
DESCENTが有名だったかな
https://ja.wikipedia.org/wiki/DOSエクステンダ 富士通の公式サイトに富士通の歴史の一部として Towns の記述はあるよ。
結果的に廃れたけど黒歴史ということはない。 当時はそれなりにユーザもいた。 >>751
NHKはまだ産まれ変わってないから「わが社の黒歴史」に出る資格が無い >>755
この前はYAMAHAのFM音源が「わが社の黒歴史」に出てたよ 16ビットの制約で64キロバイトメモリしか確保できない時代から
一気に4GBメモリがリニアにアクセスできるようになった時は感動しましたよ
64ビットでは、あんまり感動はなかったな、なんでだろう 勉強してなかったからテストの点数が心配だなー チラッ チラッ
みたいな番組なわけだな。 >>759
64KBを超える事より4GBを超えることの方が圧倒的に少ないからだな ちょっと本気でプログラム組みだせばコードサイズ64KBなんてすぐ超える
一方1MBなんて集団でごちゃごちゃやってないかぎり超えない アセンブラで組めばそんな大量のデータサイズにならんよ データじゃなくてコードサイズの話なんだけど
ちょっと凝った仕様を入れようとすると64Kbくらいは簡単に超える
泣く泣く削るか無理して分割ロードにするか
8ビット時代はそんな感じだったな 昔のPRGとかメニュー開くとCDアクセス始めるゲームとかあったなぁ。
メモリー足りず、フィールド、戦闘、メニュー毎にプログラム読み直してるのかと思った。 Turbo C++ の MS-DOS 版にダイナミックロードを補助するライブラリが付いてなかったっけ?
うろおぼえだけど。 >Turbo C++
TurboがC++だった頃なんてあったかな あった
>1990年5月、ボーランドは Turbo C から Turbo C++ へと移行し、アマチュア向け・ローエンド製品を
>Turbo C++、プロ向け・ハイエンド製品を Borland C++ として2系統に展開した。
https://ja.wikipedia.org/wiki/Turbo_C DOSでも増設メモリに32bitレジスタでアクセス出来たのなら・・・ それがDOSエクステンダだろ
GO32には世話になった 黒歴史度はFM-TOWNSとX68000とどっちがどっち? 何が黒歴史だ
どっちも国産パソコンに革命起こしたんだよ TOWNSやX68000の話というのは、
PCやOSの話題にはなってもC言語の話題ではない >>775
パソコンでありながらゲームしか宣伝してなくて当時発達著しかったゲーム機に負けただけで革命もクソもねえw ゲーム機とPCで切磋琢磨してたんだろ
ゲーム機にだって栄枯盛衰はあぅたよ
そういえばプレステにLinux入れてアプリ作って動かしてた人いたなあ
プレステは高性能すぎて、特定国への輸出が規制を受けてた PlayStation3に採用されたCPUはCell、ソニーとIBM、東芝の共同開発だった。
この辺もWikiを読むと面白い >>778
PCがグラフィックボードに力を入れだすのはウィンドウズ普及以降になる
ゲーム機にはニンテンドー64のRDRAMとかセガサターンのシンクロナスDRAMとかアーケードやシリコングラフィックCGマシンから取り入れられた新技術が投入されX68000やタウンズのかなう相手ではなかった X68やTOWNSはMD/SFCとの争い・・・
・・・PS1 ジャンピングフラッシュの元になったゲームはX68で作られたんだっけ?あとワイヤーフレームのスターウォーズも。 (それって昔のPC板やレトロゲー板の範疇だからそろそろやめてくんないかなここはC言語スレ・・・) 68000は素晴らしい。8086のようなセグメントのあるCPUはクソだ。
と当時は思ったものです。 X68000は素でgccが動いてうらやましかった。
一方86はgo32で無理矢理動かしてた。
Cに戻してみた。 レジスター数は羨ましかったな
あんだけあればレジスターだけでプログラム動かせそう、とか アセンブラやるとね、バイトの並びが上位桁が先に来るので人間に分かり易くて良い、みたいな話もあった。
68000 だけじゃなく 6809 とか 6800 とかの 8 bit CPU の頃からいわゆる68系はそうだったな。
Sun の Sparc もそうか。 80系は昔からリトルエンディアンだったな。アドレスの小さい方が桁の小さい方にした方がコンピュータ的には自然だと考えたのかも知れない。 リトルエンディアンは同じアドレスから読み取ると
16ビットデータを8ビットレジスタで読んでもちゃんと下位8ビットが読める
ビッグエンディアンは上位8ビットが読み込まれてしまう
さらに68000は16ビット以上は奇数アドレスから読み込めないという制限があるのでハマることもある リトルエンディアンの場合は、図を描くときに右から左、下から上に番地が増えるようにすると合理的なのよね
ダニーコーエンの、エンディアンの語源になった文書にもそんな図があったと思う。アスキーアートだけど
https://ja.m.wikipedia.org/wiki/ダニー・コーエン_(計算機科学者) 8bitCPUの頃のCPUの加算器は16bit+16bitしかできなかった、32bitの加算は分割してやるしかない
加算を分割してやる時は下の桁からやる
上の桁からやると、下の桁で繰り上がりが発生したら上の桁に戻って繰り上がり処理することになるから
下の桁が前にあるのがリトルエンディアン、こっちの方が自然だと思う
ビッグエンディアンはデータを後ろから前にアクセスしていくことになる、それだけだって言えばそうだけど キャストしやすさもあるな。
メモリ上にある int 型のデータを char にキャストするみたいなとき
リトルエンディアンなら単にその場所から 1 バイトを読みだせばいいだけだが、
ビッグエンディアンだとアドレスをずらして読みだすか
読みだしてからマスクするかになる。
まあそのへんは効率的に処理できる命令があったりするんだろうけど
そんなこと最初から考えずに済むならそのほうがいい。 まあでもネットワークバイトオーダーはビッグエンディアンになっちゃってるんだよね。
これはこれで理由があるのかも知れないが、とにかく80系CPUだとひっくり返さねばならなくなった。
結局C言語だとそういったCPUの違いを吸収するために htonl(), ntohl() のようなマクロまたは関数を使うことになると。 それは、そういう風に決めないと、処理出来ないからだろう 通信系はなぁ……。 結局は通信相手と同じ規約を使うしか仕方がないから
個々のコンピュータ (アーキテクチャ) にとっては不自然になることもある。
モダンなプロトコルはリトルエンディアンを採用している事例もそれなりにあるよ。 そのエンディアン変換が68000は面倒で
例えばZ80なら16ビットを上位バイト下位バイトレジスタ間で3命令で交換できるのに
68000はメモリに16ビット書き込み、8ビットシフト、メモリから8ビット読み出しという手順をしなければならない(確か)
万能のCPUなんてないものだと思ったよ 「インディアン」は何かの差別用語に該当しないのな
戦争に負けるとはこういう事だぞお前ら アメリカ発見したとき(これも本当はおかしいことなんですが)、
そこがインドだって思いこんた白人がつけた呼び方だから
本当は間違いなんですけどね
そのインディアンと、エンディアンは別の言葉です >>799
68000で16bitのd0.wの値をエンディアン変換
ror.w #8,d0
68000で32bitのd0.lの値をエンディアン変換
ror.w #8,d0
swap d0
ror.w #8,d0 SJISがBEじゃないのはなんでだろうね
MSはアホだったのか? 間違えた
SJISがLEじゃないのはなんでだろうね
漏れがアホだった 質問の意味が分からなかったんだが
2バイト文字の上位、下位の順番のことかな? もともと日本メーカー(多分NEC)が策定したような気がする JIS コードでの概念としては第一バイトが区、第二バイトが点に対応するようには設計されてる。
2バイト整数の上位と下位ではなく「第1バイト(区)」「第2バイト(点)」の組なんだよ。
Shift_JIS はアスキーコードと共存できるように JIS の配置をずらした。 (だから Shift と名前がついてる。) ここはCを知り尽くした老害の集いとみなせ
常に話題に新鮮さが求められる
流れを変えたくば新鮮なC言語の話を振ればよい C23 の話題なら……。
今回の変更は割とデカいし。 C11も大して使われてる気がしないところでC23なぁ いつだったかコミケの第何回かの略称と紛らわしかった思い出 >>820
まあ強いて言うならSJISはビッグエンディアン固定だよね >>821
エンディアンというのは数値にしか成り立たない概念でしょ
UTF-16はエンディアンの区別があるけど、これは16bitの数値だからあって当然だけど、SJISは単なるバイトストリームでしょ
なのでエンディアンの区別は無いはずだけどね
SJISが16bitの数値として定義されてんなら、何かソースを教えてくれよ C言語はOSの仕様とセットだから、どのOSのC言語か書かないと意味がない。 SJISにしろJISにしろ98/88で使おう(テキストVRAM書き込みや漢字ROMからの読み出し)
とするときはなんかよくわからん変換やらされた思い出・・・。 >>817
constexpr、nullptr、auto
C++で便利だったやつが追加されるんだ >>817
constexpr、nullptr、auto
C++で便利だったやつが追加されるんだ >>822
文字コードは数値だと思ってたけど違うの?
ソースに似てるけどソートは出来るよ アナル可変長形式は数値じゃあないのか
勉強になったわセンキュー>>882 アナル可変長形式ってどんな形式だべ?
太さによって広がりはするけど長さは…… SJISって1stバイトの最上位ビットが立ってるのをもって
後続バイトがペアになるわけだが
ここからエンディアンへの繋がりを見出だせない >最上位ビットが立ってる
もうちょっと複雑だったと思う
UJISとは違う SJISはコード表見てて文字列を1バイトづつ見て行って
0x81~0x98、0xe0~0xeeが出てきたらSJIS文字だと判断するコード書いてた。 あと文字列操作コード書きやすいように1文字2バイトに変換(?)するコードも書いてた。 >>827
> SJISが16bitの数値として定義されてんなら、
と書いてあるだろ
数値だと思ってたけどとか、読解力が無さすぎて泣けてくる…
JISコードは16bitの数値(2byteコード)としても定義されてるけど、SJISはそれを巧妙にエンコードしたものと言えるだろう
なのでやはりバイトストリームだな テキストファイルの形式としてSJISはビッグエンディアンでなければならないって程度の認識。 SJISを文字と数値の相対表と見るか、
テキストのファイル形式を含めた規格とみるか。 いまどきキャラクタセットの操作を自作してしまうのはヤバいプログラマ 昔書いたunicode対応のソースが最新コンパイラでエラー、ワーニングが山程出てきて心折れるんや・・・。 文字列としてリトルエンデアンだと可変長文字コードが面倒な事になるでしょうに >>824
漢字ROMとVRAMはエンディアンというより(エンディアン)もあるが
ややこしかったのは右半分と左半分とかな >>840
"Aア"は0x41 0x83 0x41だけどこれがもし0x41 0x41 0x83だったら、0x41 0x41まで読んだところでこれが"AA"なのかどうかを次のバイトまで読まないと確定出来なくなるわけだよね >>835
どのあたりが巧妙なのか ついでに解説をお願い思案す x 巧妙に
o 泥臭く
EUC-JPで良かったんだよ EUC-JPにすると半角カナ文字が全滅するんだよな 半角カナは全滅してほしかったし
今すぐにも全滅してほしい もう面倒だから Unicode を UTF-8 で使え。 euc-jpの半角カナは全滅じゃなくて、バイト数が多くなる、だったような。3バイトとか >>843
JIS X 0208はいわゆる半角文字も2byteコードで定義されてるが、それと半角カナをエスケープシーケンス無しで混在させる方法を定義したんだよ!
ほぼWikipediaの受け売りだw
詳しいことはWikipediaを見ろよ
つうかそんなことも分からん若造が増えたんだな… >>848
2バイト。 0x8e が最初にあって、その次にシフトJISの半角仮名と同じコードが来る。 文字コードも、32bitとか、64bitとか、メモリーアクセス単位に見合うサイズにしたらいいだけだよなぁ
可変長にする必要が全く無い 80年代プログラマ「1バイト、1ビットでも無駄にするんじゃねぇよ!!」 1文字に見える絵文字もUTF-8で41byteになったりするんで、1文字64bitにしようが可変長になる
なのでUTF-8かUTF-16にしておくのが無難
UTF-16は主な漢字は2byteで済むんで、何気にバランスが良い文字コードだと思えるようになってきた >>824
表示コードだろ
SJISにしろJISにしろ表にすると空白部分がいっぱいあってROM容量がもったいない(当時は)から >>852
まあ数百文字しか文章を書かないプログラマーの発想だねえw
数万文字や数万ページの文書になると保存や検索にリソース食ってもったいない >>853
2KBに無理矢理詰め込むみたいなことを昔やったことあるな。ROMの容量に合わせてビット単位で詰め込む。
そういえば Apple ][ のモニタプログラムが2KB丁度で6502のアセンブラのソース見て物凄い詰め込み具合に感動した。
1バイトも無駄がなく2KBピッタリだった。 > 1バイトも無駄がなく2KBピッタリだった。
そんなことない。まだ詰めれるし空きもあった。 >>858
えー。なかったと思ったがなあ。それって Apple ][ plus とか、後に出た少し変えたやつでは? >>850
おお、指摘サンキューです
アップル2とか
マニアック過ぎて付いて行け
ま アリスソフトのゲームはひらがながカタカナで入っててうふ~んだったな linuxのファイルディスクリプタの操作に関する質問です。
別デバイスとのシリアル通信制御にselect関数を使用しています。
受信可能かタイムアウトかを判断しているんですが、別デバイスから電文が送られてからselect関数が受信可能を検知するまでに20msほどかかり、その後のreadしたサイズは32ビットほどです。
理想は5ms以内で受信可能を検知してほしいです。
ボーレートは80000bps(カスタム)
システムコールを使っている以上、デバイスドライバ。いじらないと難しいですかね? >>864
ラズパイです
32ビットではなく32バイトです
送っている電文も32バイトです ちなみにselect置かずに、ノンブロッキングでループでreadした場合も、少しずつreadできるわけではなく、20ms後に送った電文全てがreadで読み取れます そもそもデータは実際どれくらいで到着してんのか確認はしたんだよな?
送信側が20ms毎にしか動いてないかとかその辺も 16bit sensation 観てるけど
https://16bitsensation-al.com/
出て来るPC画面の編集中のアセンブラが
32bit用のコードじゃん >>865
200バイト送ってみましたが、検知の時間差はあまりありませんでしたが、read1回で200バイト全部取れました… ラズパイのスタックがバグってるだけだろ
他の環境でも試したのか? パケットサイズ貯まるまで送信しないか
貯まらなくても時間で送信だったかなぁ >>877
その辺は設定で変えられるんだよ
rawモードにすれば両方無効になる プロになると、Linux は3回 shutdown しろと言う香具師がいるw
Windows に至っては、
shutdown はダメ、再起動しろってさw
どういうシステムやねんw >>862
それ何かの都合でどうしても必要だから NOP にしてあるのでは? まあでも開いてると言えば開いてるな。
とすると2KB未満であの機能が詰め込まれていることになって、余計に凄い感じするわけだが。
まあでも逆アセンブルが出来るのにその文字がソースに入ってなくて、一体どうやっているのかと延々と
プログラムを読んで、確か2バイトに3文字詰め込んでて(f9c0, fa00 の辺り)、当時それを見つけて驚いたな。
初心者だったからね。 3回shutdownは初めて聞いた
3回syncのことかな?
1回目が依頼、2回目が実行、3回目は祈り・・・ スマン。3回shutdown じゃないわ。
3回sync だった
Windows は高速スタートアップがあるから、
shutdownはメモリの内容をSSD に保持するから、復元されてしまうので、
再起動するのが正解らしい 説明がヘタで何言ってるのかわからんが
このスレッドのテーマと関係ないだろ他でやれ 一回目の sync に時間がかかるとその間にメモリの書き換えが起きてしまう可能性があるから、二度目の sync をする。ふつうはそこで満足する。どうしても心配ならもう一度 sync するわけだけど、そこまで心配なら別の方法を考えた方がいい。 888888888888888888888888888888888888888
888888う8888888888ん88888888888888888こ88
888888888888888888888888888888888888888 CでWindowsのデバドラ描くなら
shutdownが高速スタートアップかそうじゃないかは重要じゃないか
cmd 起動して shutdown -s -t 0 をよくやる
これだけじゃなくて hybernate をあらかじめ off にしておく必要もある
powercfg.exe /hibernate >>887
1回目のsyncはコマンド実行後にすぐ返るけど、
2回目のsyncは1回目が終わるまでブロックされるんよ
だから書き込み保証の代わりになってたってわけ
3回目は祈り・・・ 三菱UFJ銀行など10金融機関で約250万件の送金が滞った全国銀行データ通信システム(全銀システム)の障害は、各金融機関と同システムをつなぐ機器の容量(メモリー)不足が要因だったことがわかった。機器の更新で処理量が増え、想定の容量を超えてパンクした。事前のテストが不十分だった可能性もあり、検証が求められる。 記事読んでると、素人が作ったのかと思うほど粗雑に感じるが、
単に記事を書いた記者が素人だからかもしれない。 ルーターのNATテーブルが貧弱で
定期的に再起動しないといけないルーターがあったのを思い出した それなんてcorega?
ってフレーズも懐かしい・・・。 最近じゃ組み込み系もPythonになってるらしいな ArduinoとかはまだC/C++が使われているけどRaspberryPiあたりではPythonが使われている コンパクトなバイナリーが作れるんだろうか
それともライブラリーが別途必要? >>903
通信プロクシとテストデータ作成ツール^^
しょうもない物しか作ってないわスマンな 作っていて、恥ずかしさを感じないとすれば、それこそ失格だ
人は失敗の中から多くを学ぶ 恥とかそんなのとは違う
ビジネスとはスピードと品質のトレードオフ
そのバランスを考えられないのがプロとして恥 >>911
太宰治の人間失格とかけてんだろ
気付いてやれよ >>900
それってLinuxではないOSで動く場合?
Linux入れちゃったらドライバとそれに対するライブラリだけの問題で言語は関係なくなるよね。 自分で調べろよそれぐらい…お前もプログラマー失格やな! C23でC11ぶりに更新ってC標準化委員会(?)だかはサボり過ぎじゃねーか。
C++なみとは言わんが5年ぐらいごとに見直せや。
nullptrとか入るの遅過ぎる。
deferも無いとかアホすぎる。 いつまでも未完成のサグラダファミリアみたいなC++とは違ってCは生まれた時から完成してるから
後々機能追加したところでそいつの自己満でしかない
未完成のC++から逆輸入されて良かったことなんて行コメント程度しかない コンパイラがC11のgets_s()関数に対応してないんですが、どうすればいいですか? コンパイラがC11のgets_s()関数に対応してないんですが、どうすればいいですか? >>923 あきらめてvisual studioでgets_s()関数を使えていますが、vscodeの普段使っているコンパイラでは
使えません >>923 あきらめてvisual studioでgets_s()関数を使えていますが、vscodeの普段使っているコンパイラでは
使えません 自分で書いたってそんなに時間はかからんだろう。
行がバッファより長いときや引数が条件を満たさないときに
制約ハンドラを呼ぶってだけだぞ。 >>926 結局gets()関数の代用はfgets()しかないというこですね >>920
そんなんだからリーナスだってぶち切れるんだぞ。 winでguiアプリ作る時とかCランタイムなんて全く使わないでしよ
今更Cで作るかは置いといて 文字列周りのあれこれは Cランタイムのお世話も併用することが TCHAR無視でASCIIzしか使わないならいけるかな
memcpyとかmallicとかも普通に使えるしな
TCHARのUNICODE版の文字列処理ってもうCランタイムと言うのは無理ありそう
末尾にに_s付いたのとか先頭にl付いたのとか
もう亜種増え過ぎで覚えられんくなった
あれはCランタイムじゃなくてwin32apiだわ C言語でGC実装したライブラリあったよね
あれって今でも使われてんの? >>936
そうそうそれそれ
思い出したけど w3m とかで使ってたよな
w3mが現役ってことはboehmgcも現役なんかね Boehm GC使ってるぞ
つうかUnityのランタイムはBoehm GCが使われてる Unity使ってるゲームはごまんとあるけど、敢えてGCを切ってるゲームも中には有るかも知れんが、ほとんどのゲームは裏でBoehm GCが動いている
要するに知らないだけで、Boehm GCはメチャクチャ使われてる
無知は罪だなw > ほとんどのゲーム
ほとんどのUnity使ったゲームでだな
それと最近UnityのBoehm GCにインクリメンタルGCが追加された
それまではStop The World(STW)のインパクトが凄くて、みんな最後にはなるべくGCが発生しないようにするチューニングが待っていたw Boehm GC はマシンスタックも走査するようなデザインだからアーキテクチャに依存する部分がいっぱいあるし、メンテナンスもし続けないとすぐ実情にあわなくなって破綻すると思う。
逆に言えば採用されてちゃんと動いているのはちゃんとメンテナンスされてるからだろう。
それなりに活発に利用も開発もされてると言えるんじゃないか。
プログラミング言語処理系のいくつかで採用事例を見たことはある。 今も活発に開発されてるよ
まぁリリースは半年とか年一ぐらいだけどね そうなのかUnityすげーな
そもそもUnityがC言語だったのも知らんかったわ
C言語でGUIなゲーム作れるならやってみるわ
ありがとう ゲームのMOD管理や改造ツール探してると結構間違ってソース配布ページへ飛ばされる。
ファイル拡張子が*.cなトコは無いにしても、*.cppなとこは多いね。 >>943
dotNET が Unity の基礎にあるからユーザが使うレイヤでは C# が前提だよ。
ただ、それを実行するランタイムサポートの中には低レイヤ寄りの部分も当然あるし、
そこで Boehm GC が使われているって話。
C で書いたモジュールを呼び出すことは出来るんだけど…。
「C でゲームを作る」のがやりたいなら Unity は全然向いてない。 そもそもC言語でGUIゲーム作れるじゃんUnityじゃなくても Windowsのクロンダイク作ろうぜ
あれならもともとCのはず MS-DOSの頃はアマチュアの作ったゲームがたくさんあったな
ゲームメーカーの商品より優秀なのもあったし、
メーカーから訴えられた個人もいたな。
メーカー側が取り下げた様だが、
もしかしたら訴えた事実がなかったかも知れない
その後倒産したという噂を聞いた
Windowsになってからは、VBで作る人が多かった アマチュアが作っているゲーム作品の数で言えば今のほうがずっと多いと思うが。 そうなのか・・・
最近はゲームしてないので知らないんだw 今はvやutuberに媚びたゲーム作れば配信で遊んでくれるから一気にプレイヤー数も増えるよ >>957
Bio_100%とかタカリスなんて知らないせだいなんだろうな ゲームエンジンもライブラリもろくになかった時代にC言語とアセンブラを駆使して
高レベルなゲームを作れるアマチュアプログラマがたくさんいた
(Unityで作るより高スキルが求められる)という話であって、
アマチュア/インディーズゲームのリリース数が論点というわけじゃないんじゃね?w 1997年あたりにワイヤフレームだけどゴリゴリの3Dで8台で競艇するゲームは当時かなりオーパーツ感あった
波でグラグラゆれたり、あの当時でステージメイキングも確か出来たし、誰か知ってる人おらんじゃろうか C言語標準規格、せめて5年毎ぐらいに見直してくれればなぁ。
そしたらとっくにnullptrは入ってただそうし。もしかしたら deferや lambdaも入ってたかもしれん。 規格に対してまあそういう考えの人がいるのも分かるが、全体としては改定に対しての需要というか声は小さかったってことでしょ どれも今更すぎていらんわ
そういうの絶対必要って奴はとっくにC言語ではない何かを使ってるでしょ >>962
C17 がわずかな保守で終わってることから察しなよ。
見直した結果として変更が要らんという判断をしたんだ。
C に defer を入れる意味はない。
提案として出ている以上は欲しいと思う人もいるんだろうけど。
あれは panic とかがあっても後始末するというところが価値なので
そういうのがない C で関数の終わりに後始末したけりゃ関数の終わりに書けばいい。
例外処理も含めて入れるってのだとなおさら無理だと思うし。
いまさらランタイムを分厚くする方向の機能を言語コアに入れるのは賛成を得られるはずがなさそう。
ラムダ式はまだ可能性がなくもなさそうに思うが……
C++ のラムダ式は暗黙のクラス定義の構文糖として定義することで詳細な規定を
大幅に別項目に丸投げ出来ている。
C で理屈をきちんと整理するのはちょっと難しくない?
キャプチャを全く諦めるならあり得そう。 継続メンテナンスが必要なのはだいたいC89の頃のプロダクトだったりするので
C言語自体の規格アップデートはさほど必要とされていないのね モダンな機能が必要なら C++ を使えばいいって言えてしまうってのもあるしな。
C23 は刷新が大きいけど、新しい機能を入れるというよりは
あまりにも駄目すぎるところを (C++ の後追いをする形で) 改良するって感じだし。 C99 からの無名構造体は廃止してほしいねえ、あれでC++との互換が失われた。
構造体にコンストラクタを記述できるようにした方がマシだったと思う… C99 からの無名構造体は廃止してほしいねえ、あれでC++との互換が失われた。
構造体にコンストラクタを記述できるようにした方がマシだったと思う… >>968
コンストラクタこそ要らないだろ。
関数として書けば済む話だから。
ああいうのは色んな機能と連携して便利になるので
個々に見てしまうとたいして便利ではない。 >>968
Cでtypedef+無名構造体/共用体のペアはstruct tag書式より使われてると思うが
これはstructをいちいち書かされるC固有の仕様の問題であって、C++では最初から型宣言自体のやり方が違う
つまりCの仕様をC++に合わせる意味は無く、C++との互換性はどうでもいい >>965
例外の無いCでのdeferの意味は、単に後処理(デストラクタ)をコンストラクタ(Cではmallocや初期化関数)の直下に書けるという意味がある
関数の下に書けばいいといっても、gotoで飛ばしてんじゃ、プログラミング言語として欠陥が有ると思うよ
goto使うな→エラー処理で使えば綺麗に書けるよ!って、やっぱおかしいだろw defer って分からんのですが、関数単位での atexit() みたいなもの? double* q = malloc(something);
defer { free(q); }
↑これ見れば一目瞭然だな
exitと関数やブロックを抜ける時に発動する
けど、Cは書かれた通りに動くという前提を少し逸脱してんだよね
それでも絶対便利ではある
難しい問題だな 合ってるよね、うん
それ(他言語の defer 相当機能)って、問題解決にC言語を採用する環境では、OS上のプロセスの切り出し単位の設計、にマッピングすれば済む事ではないのかな?
建設的な議論の参考ネタとして:
perl言語が嫌われた理由の一つに「同じ事をいろんな書き方で書ける」言語設計ポリシーがあって、それは他人が書いたコードをメンテする立場だと「あらゆる書き方に精通してないとメンテできない」デメリットになり
pythonはそれを反面教師として「同じ事はだいたいみんな同じ書き方になるような言語設計を目指す」ポリシーにした、と認識してます ああ、ブロック単位なのね…
とすると、上手なC言語のプログラマー達が習慣的にやってきた方法は以下ですよね:
■実装すべき処理を関数にマッピングするとき(主処理、失敗時処理を)細かく分ける
■関数をイベントハンドラとして「登録する」流儀の ミドルレイヤを書いて、そのミドルシステム上で 実装対象の「意味のある処理単位」を書くよう、プロジェクト単位でコーディングルールを定め、守り&守らせ
■◯◯失敗時には△△を行う、を明確に設計し実装して、それが分かりやすい納入プログラムとする
で解決してきた、と思います。
つまり defer 機能がなくても同じ事をやる手法は既に確立している。
前のレスでの主張と合わせ、defer 機能を追加しないのが正解、と言いたいです breakでいつでもブロックを離脱できればgotoより明確でスムーズでかっこよくdeferっぽいことできるよな >>978
{int rc=0; do{ ★始め
処理
rc=1; break; ★失敗した
処理
break; ★成功した
} while(0); if(rc) { ★
異常時処理
}} ★終り
とかそういう話?
こういうのを #define で「エセ構文糖」みたいに定義する人もいますよね。(自分はあまり好きじゃない。格好悪いと思う)
C言語用の単体テストフレームワークで unity ってのがあります。unity ではテストコード内で 独自の try ~ catch 風文法を書けるのですが、それがまさに (setjmp longjmp も使って) #define でエセ構文糖風に実装してました。需要があれば再度調べてここで概要報告しますw >>975
Go の defer に倣うなら defer 文に書けるのは関数かメソッドの呼出し。
(式一般、文一般を書けるわけではない。)
呼出しは関数の末尾だが引数は書いてある場所で評価されるというルール。
C 風の文法で書くなら
double* q = malloc(something);
defer free(q);
q=NULL;
return;
というように書いても malloc した場所はちゃんと free されることになる。
このルールのおかげで前準備と後始末を近い場所に書けて「対応関係は」一目瞭然と言えるが、
そのために変則的な評価規則が入ってるわけ。
式単位での順序が入れ替わるってだけじゃなくて引数の評価と関数の呼び出しが
分離されるってだいぶん変な仕組みだよな。 >>973-974
Nim の defer 良いよね >>973-974
Nim の defer 良いよね 正常ルートは終わる時 q==NULL なのに、その前の
defer free(q) したときのqの値でfree() するんですね
うへぇ…
誤解釈してバグ出しそう
てかこれは、ひねり出された意地悪サンプルで…実際のプログラミングでdefer式が効果的となる使用例ではない、ですよね? この話で改めてあぶり出されるのは、
あるプログラミング言語を深く理解して「書ける」「読める」ようになることには「自分なりの 上手なエラー処理の書き方 を探して身に付ける」事が含まれる、って事ですよね。
それは人類の資産なんだけど、実際の存在場所は あまたのプログラマー達の脳内 であって、一朝一夕に書き換えられる物じゃない。
だから言語仕様を改定して新機能を足すのは、新言語を作る時よりは慎重になる必要がある、と解釈しました >>984
Go でどうだか知らんけど C に defer を入れたとしたらというテーマでの話なら
malloc と free を対応づけるのは考えられる用途の筆頭でしょ。
逆にこういう変則的な評価規則を持ち込まないとしたら、
つまり defer 文に書いたものが単に return の直前に評価されるだけということにしたら
途中で書き換えられる可能性が出てきて
前準備と後始末が対応づいているかどうか一目瞭然とはいかなくなる。
どこかしらでなんか汚い感じにはなるよ。
そういう汚さを受け入れてもなお欲しいほどの利便性かというとやっぱり疑問は残る。
汚さを受け入れていいなら goto の汚さを受け入れるのとそんなに差があるとも思えないし。 >>980
意地でもgoto使いたくない時にはそれでもいいけど、それの欠点は中にswitch文を書くと、breakで抜けれるのはswitch文からだけになる事だな
自分ではwhileを抜けた気になって実は抜けてないという、微妙なバグを生み出す可能性があるなw >>988
do {...} while(0)
なので、必ず1回実行し、2回目はないです >>989
適当だけどこういうことでは?
{int rc=0; do{ ★始め
処理1
siwtch(x){
case 0: rc=1; break; ★失敗した ※siwtchから抜けるだけでwhileからは抜け出せていない
case 1: break; ★成功だけど処理2は実行しない ※siwtchから抜けるだけでwhileからは抜け出せていない
case 2: break; ★成功で処理2も行う
}
処理2
break; ★成功した
} while(0); if(rc) { ★
異常時処理
}} ★終り >>990
おっしゃる事、分かります。具体的に書いてくれてありがとうm(_ _)m >>987
はい…
mallocとfreeを確保と解放の例とするのは異論ないです
deferより一つ上位の話は、エラー処理をバグなく、分かりやすく書こうというテーマだ、で合ってますよね。
その上で、deferがないとこんな面倒なのが、deferがあるとこんなに分かりやすい 例がよいのです
確保と解放の書き方検討で、私が検討するのは例えばこんな感じです:
■(1)ある意味のある処理単位が、リソースを 2個以上使う 場合を考えると、1個の場合より検討がよく進む。特に、
■■(1a)初期化が途中で失敗した場合、すでに確保が成功してしまった資源をどう解放するか
■■(1b)資源の変数は最初に、確保処理のエラー戻り値と同じ値で初期化をすると、スッキリする事が多い
■(2)正常ルートでの解放と、エラールートでの解放で、コードを共通とするか、別とするか。
■■(2a)確保、主、開放 の処理を、同じ「関数」で書くのと、別の「関数」に分けるのはどちらが良いか
■■(2b)「goto エラーラベル;」を好きか嫌いか
■(3)プログラマーによる解放処理の前の 「if(確保済みなら)」のガードが、必要なもの(fcloseなど)と、不要なもの(free)があるので、マニュアル確認は要る
もっと語りたいけど、レス分けます、というか時間を置きます。あまり一人が語りすぎると、嫌がる人もいますよね てかキータで書いて、皆さんの意見を聞いて修正していったり、してみようかな… とりあえず次スレ立てました。即死防止の保守書き込みは要らない、で良いのかな?
C言語なら俺に聞け 162
https://mevius.5ch.net/test/read.cgi/tech/1698653580/ >>994
乙。
あなたの男気に女気に惚れました。 Golang の defer はあくまで関数の終わりまで遅延させる (ブロックの終わりではない) ので
呼び出される defer の個数が動的になりうるんだな。
https://go.dev/tour/flowcontrol/13
この挙動も C には馴染まなさそうだな。 俺は某画像ライブラリのリソーストラッカーみたいに開放が必要な物を全部紐付けて後で開放する仕掛けを使ってる
まあCには何にも縛られないのが良いんだし好きにしたらいいよ 構文的にはC#っぽく
using (double* p = malloc(...); free(p)) {
p を使う
}
でも良いかも知れない
これだと1ループのforに似ててCに良く馴染むな
もちろんreturnとかexitで脱出してもfreeは呼ばれる このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 192日 20時間 14分 5秒 5ちゃんねるの運営はUPLIFT会員の皆さまに支えられています。
運営にご協力お願いいたします。
───────────────────
《UPLIFT会員の主な特典》
★ 5ちゃんねる専用ブラウザからの広告除去
★ 5ちゃんねるの過去ログを取得
★ 書き込み規制の緩和
───────────────────
会員登録には個人情報は一切必要ありません。
4 USD/mon. から匿名でご購入いただけます。
▼ UPLIFT会員登録はこちら ▼
https://uplift.5ch.net/
▼ UPLIFTログインはこちら ▼
https://uplift.5ch.net/login レス数が1000を超えています。これ以上書き込みはできません。