0からの、超初心者C言語相談室
■ このスレッドは過去ログ倉庫に格納されています
何にも知らない0からの出発、超初心者のためのC言語相談室 C++は、こちら。 0からの、超初心者C++相談室 https://mevius.5ch.net/test/read.cgi/tech/1542002113/ #include<stdio.h> void funcB(void) { int b = 20; printf("b-address: %ld\n", (long)&b); } void funcA(void) { int a = 10; printf("a-address: %ld\n", (long)&a); funcB(); } int main(void) { funcA(); return 0; } (1)変数aとbはメモリ内の特に何という領域に確保されますか。 (2)変数aとbはどちらのほうがより小さい番地にメモリが確保されましたか。 (3)(2)から(1)の領域は前と後ろのどちらの方向へ向かって利用されていくと推測できますか。 スッキリ分かるCの問題なのですが これの(3)が意味分からないので解説してほしいです (2)も何でそうなるのかよく分からんですが、。 >>4 pythonでもid(obj)で番地見れるからおんなじだよ 変なのpythonスレに誘導するような言動は謹んで頂きたい >>3 (1) 一般にはスタックと呼ばれるが言語仕様にはそのような規定はないので、 実行環境によっては違うこともあるかもね。 (言語仕様ではオブジェクトの寿命が決められているだけ。) (2) 主流の CPU では b の方が小さい番地の可能性が高い。 (3) スタックはメモリの上位番地から下位番地に向かって使われる。 なんでそうなるかっていうのは結局のところそう決めたから そうなっているってだけなんで、逆でもかまわないし、 実際に逆にデザインされたアーキテクチャは存在する。 https://ja.wikipedia.org/wiki/PA-RISC これらはコンピュータアーキテクチャの話。 言語の仕様とそれがどのように実装されているか (機械語を生成するか) は別物なんで、 そこらへんのレイヤを区別して考えないとわけわからんと思う。 >>9 ありがとうございます! 本に書いてない内容だったのでスッキリしました。 strstr で文字列を検索出来ますが'\0'が含まれているともちろん正常に動作しませんね メモリ中の'\0'を含むバイトパターンの現れる位置を調べる関数は何ていう名前? >>11 標準には無い。 POSIX にも無い。 glibc には memmem があるので場合によってはそれが使えることもあるかもね。 memchr を使って memmem 相当の関数を造りました ありがとうございました ところで memmem の引数や戻り値ってどうして void * なんですか? char * になってないと使いにくくないですか? memory 用だからですか? void * の場合 size_t が各要素の size の倍数なのか char の size の倍数なのか 特別考慮してくれる訳でもないですよね? >>13 > memory 用だからですか? そう。 バイト列を扱う場合というのは色んな型のメモリブロックである可能性がある。 `void*` の特徴として、他のポインタとの間で暗黙の型変換の対象になるという特別扱いがある。 (C++ ではこの特徴は廃止されているので注意!) だから int a=114514; unsigned char b=0xbf; memmem(&a, sizeof(a), &b, 1); といったように何のポインタを渡した場合でも型が違うとかいったエラーにはならない。 いちいちキャストしなくてよいから楽だからこうなってる。 ちょっと間違えた。 C++ でも void* への暗黙の型変換はアリだけど void* からの暗黙の型変換はないんだった。 環境 unix系でxterm系のコンソール less vi emacs等の 現在のプロンプト位置でプログラムを実行し(全画面表示し)終了すると 元のプロンプト位置(の次の行)に戻ってくる処理をできる限りの低レベルで知りたい 例えば 3行目でvi起動 編集 終了 プロンプトが4行目に復帰する 起動時のコマンドが直上にある状態 エスケープシーケンスでのクリアは内部的に エコーしないで改行してるだけ?なのかそのまま空行が出来てしまう char a[4]; で確保したときって strncpy(a, "abc", sizeof(a)); で良いんですか? char a[4+1]; で確保する書き方もあれば strncpy(a, "abc", sizeof(a) - 1); で少なめに指定する書き方もあるようですが どちらが一般的ですか? strncpy(a, "abcd", sizeof(a)); ならメモリ壊れますか? char s[4] strncpy(a, "abcd", sizeof(s)); はnul文字がコピーされないし strncpy(a, "abc", sizoef(s)-1); もnul文字がコピーされない 唯一動作するのは strncpy(a, "abc", sizeof(s)); だがこれも abc が abcd になったらnul文字がコピーされなくなる 結論:strncpyは使うな 正直標準ライブラリは諦めた方がいいと思うんだが 安全な文字列や数値型ライブラリはあるけど、特にどれがメジャーというわけでもないから、チームでやると最大公約数の標準ライブラリ使わざるを得ないっていう >>16 printf("\e[?1049h"); // これで代替スクリーンバッファを有効にする printf("\e[?1049l"); // これで代替スクリーンバッファを無効にする default: https://www.mbs.jp/news/kansainews/20210628/GE00038998.shtml ■「日本が財政破綻する確率は100%」と大前研一氏。 私に言わせれば、税金を払える生産年齢人口が減り続けている以上、破綻確率は「100%」である。 今の日本は、いわば“裸の王様”のようなもので、すでに国の財政は破綻している状態だから、いつ国債が暴落して債務不履行になってもおかしくない。 ただ、それは1年後かもしれないし、10年後かもしれない、という話なのである。 そういう事態が起きないように財政運営戦略を作っていくのが、国を預かる為政者がやるべきことだ。 ところが日本は、日本銀行が「異次元金融緩和」を8年以上も継続して財務省が紙幣を刷りまくり、大量発行する国債の消化資金を民間金融機関に提供してきた。 そして、その国債を日銀が民間金融機関から買い取って自ら貯め込み、“禁じ手”とされている事実上の財政ファイナンス(中央銀行が通貨を発行して国債を直接引き受けること)を続けている。 FRBやECBも日銀と同じように金融緩和を行なっているが、むしろ日銀を先行指標として注視している。 一方、日本人の多くは、自分は国債と関係ないと思っている。 だが実際は、郵便貯金や銀行預金が金融機関を通じて国債に流れ、さらに日銀とGPIFという「2頭の鯨」が国債と株を爆買いしている。 つまり、個人金融資産は国債に化け、年金積立金も国債と株に形を変えているわけで、政府が財政破綻したら国民も一蓮托生なのだ。 だが、今の日本は政治家に政府債務に対する危機感がなく、今後も少子化と生産年齢人口の減少が続く。GAFAMのような巨大IT企業もなければ、アメリカや中国などで続々と誕生しているユニコーンも全く出てこない。このような状況では、巨額の政府債務を返せるわけがない。 では、国民はどうすればよいのか? 資金に余裕があれば、政府が財政破綻しても影響が少ない「不動産」や「金」を買っておいたほうがよいだろう。 利息が付く預貯金は元本1000万円までとその利息しか保護されないし、「株」や「投資信託」や「債券」も国が破綻すれば「国債」と同じく紙屑同然になるからだ。 ただし、最も有効な対策は、自分に投資して世界のどこに行っても稼げる人間になることだ。 もし日本が破綻したとしても、世界のどこかに繁栄しているところはあるはずだから、そこで稼げる力を磨いておくことが唯一の安全・安心・有望な投資先なのである。 4899774451 4899775067 4046019557 489977463X #include<stdio.h> #include<string.h> int main() { char str1[] = "Pointers are fun to use."; char str2[80], * p1, * p2; p1 = str1 + strlen(str1) - 1; p2 = str2; while (p1 >= str1) *p2++ = *p1--; *p2 = '\0'; printf("%s %s", str1, str2); } p1 = str1 + strlen(str1) - 1;の部分と*p2++ = *p1--;この部分の意味がよく分かってない可能性が高いので解説してほしいです str1の先頭アドレス+str1の文字数-1…でつまり何処をさしてるのでしょうか? p1 >= str1は先頭アドレスより大きい間はって意味ですか? >str1の先頭アドレス+str1の文字数-1…でつまり何処をさしてるのでしょうか? str1の最後の文字(0終端の一個前) >p1 >= str1は先頭アドレスより大きい間はって意味ですか? 惜しい 「より大きい」ではなく「以上」、=があるから VisualStudio等のIDEのデバッガでステップ実行して、 各変数の変化・ポインタの指す先を見てればすぐわかるよ *p2++ = *p1-- こういのは、意味が分からないしバグるから、MISRA-C で禁止している Ruby には、++/-- 演算子はない。 Go では単独文扱いで、他の式と組み合わせることは出来ない MISRA-C でも同様 *p2++=*p1-- これは参照してるオブジェクトの値に化けてからアドレスを進めてるんですね。 なんとなく分かりました。ありがとうございます! >>p1 = str1 + strlen(str1) - 1; ここがなんかモヤモヤするんですけど 数字で表すとどんな感じになってるか教えてほしいです。お願いします。 str1が文字列の戦闘アドレスを刺している。それに文字列の長さマイナスいちを足すと文字列の最後の文字へのアドレスが得られる。 >>31 0+25-1って感じでしょうか?今回のケースの場合 >>32 Visual C++を使ってるならデバッグ厨二、ウォッチ死期で実際に確認で切るはずだ。 C言語というのは、unix の記述言語としてスタートした言語という経緯があって、 システム記述言語だから「基本的になんでもあり」みたいな危険な言語では あるのですよ。 それを踏まえて向かいあうんだったら、ニモニックとかアセンブラとか マクロアセンブラとか、そのあたりまで含めて勉強してほしいと思う。 C++ だって、C に一皮被せただけのマクロ言語だしね。 そこは、アセンブラとの関係まで含めて、勉強しておくといいかもしれない。 ツー手も、昨今の言語だと、「そういうところは気にしなくていい」というのが 潮流ではあるんだけどね。 >>33 すいませんVCステップイン実行のやり方調べときます。 ありがとうございました。 アセンブラも覚えてみたいんですがCよりさらに難しそうなので… アセンブラの詳細を理解する必要はないんだけれど、 C で書いたものがどういう機械語に対応付けられているのかおおよそにでも 知っておくと C の仕様が腑に落ちることは結構あるとは思う。 (現代的なコンパイラは超強力な最適化があるので一対一に対応付けられるようなもんではなくなってしまっているけど……。) >>9 亀だけど、マイコン触ってるとスタック上から、下からはグローバル変数など固定配置のメモリ、 その上にヒープまたはそれに類するものがスタック間際までって割当になっててなるほどって思った。 スタックが伸びすぎても下がそこまで使ってなければぶっ飛ぶこともない的な。 スタックオーバーフローの割り込みとかありますしデバッガで様子はわかりますから気にすべきですが。 >>37 むかーし買った秋月のH8キットだったかな ペラ1枚の説明書しかなかったけどちゃんとメモリマップは載っていてなるほどそういうことか、って思った char p[]="12345"; char *p="12345"; const char *p="12345"; 先生、この違いをおしえてください。 >>41 char p[]="12345"; は char p[6]; としたのと同じように領域が確保されてその内容が "12345" で初期化される。 たとえば p[2]=6; といったように内容を書き換えていい。 char *p="12345"; は どこかの領域に "12345" という内容の文字列が存在して p はそれを「指す」という状態。 文字列リテラルは書き換えてはいけない (書き換えたらその結果がどうなるかは保証されない) というルールなので p[2]=6; というように書き換えるのは (型システム的に禁止されないにもかかわらず!) やるべきではない。 三つの例の内でこれが一番クソな仕様。 (余談だが現在の C++ では文字列リテラルは const 付きなので const を剥がして変数に代入することは出来ないように型システム的に保護されている) const char *p="12345"; は char *p="12345"; と理屈は同じだが、 p が指している領域を書き換えることは (型システム的に) 出来ない。 ロボット制御に使いたいんですが、 アドレスaのchar領域cのnビット目(0-7)をon/offするマクロはどう書いたらいいですか? 関数ではなくマクロにしたいです。 #define BitOn(a,c,n) ??????? #define BitOff(a,c,n) ??????? >>43 とりあえず自分で書いたやつがどうなるのか出してほしいなぁ。 a はアドレス n はビット位置っていうのはわかるんだけどだ c は何の指定なの? >>47 やっぱそうだよね。 unsigned char ) ~ * << |= ( 1 &= パーツを教えてやるよ。あとは自分で考えな。 すみません、質問した立場でアレですが、|=と&=は要らないと思いますw >>51 そうなのか。気になるから解決してたら結果教えて。 漏れはヘタレだから、ビットフィールド使ってRAM上で更新してバイト単位でポートに書けば良いやなんて考えちゃう。 上位ワード下位ワードを取り出すって意味がよくわからないのですが int main() { int a=77778888; } とあったら7777が上位ワードって事でしょうか? >>56 それは10進だから、まずはウィンドウズのプログラマ電卓で16進数に直して。 >>57 4A2 CFC8 となりました。あんまりWORDって意味を分かってないんですが アドレスとかの事じゃなくて符号なしshortの生の数値って意味と捉えていいんでしょうか? >>58 コンピュータの中のデータはすべてビット(0か1)の集まり int は32ビットだったり16ビットだったりするが、とにかく0や1がいくつもならべてある だけだ。 表示するのに、0111100010111101 とかだと長くてわかりづらい。 それを手短にわかりやすく表現しようと 4ビットづつまとめて表示したのが16進数 >>59 なるほど。でも取り出すって意味がよくわからないです ROWORDとHIWORDって関数は何をしてるんでしょうか >>60 LOWORD/HIWORDは、ビットシフトと型キャストをしている。Visual C++なら定義を確認できるはずだ。 >>>61 難しいのでまた型サイズやビット演算復習してからWIN32やってみます。。 解答ありがとうございました。 #define BitOn(a,c,n) ( a[c] |= 1<<c ) #define BitOff(a,c,n) ( a[c] &= ~(1<<c) ) 間違えた #define BitOn(a,c,n) ( a[c] |= 0x01<<n ) #define BitOff(a,c,n) ( a[c] &= ~(0x01<<n) ) よく使うよ 8ビット=1バイト 1ワード=2バイト=16ビット 32ビットCPUなら、通常int は32ビットで2ワード。 CPUがBEかLEか判定するのに使うマクロを #defineで描くとどんなのがありますか >>66 完全に仕様の範囲内かつ人が一切のヒントを与えずに結果が定数式になる形で自動判定するのはたぶん無理だと思う。 #define LE ( (1&0x00000001)!=0)?true:false) #define BE ( (1&0x01000000)!=0)?true:false) >>66 そんなこと考えるより環境のエンディアンに依存しないコードの書き方を学んだほうが良い。 gcc拡張なら #define LE ({ int a = 1; ((const char *)&a)[0]; }) うごくかどうかはしらん !!は静的解析やコンパイラの警告黙らせる時に使える場合もあるよ char a[3]とした場合 aとa[0]は同じ←分かる struct A a[3]とした場合 aとa[0]は違うんか? >>79 aが配列でa[0]はその先頭要素。これらは同じじゃないよ。 この関係はchar a[3]でもstruct A a[3]でも同じだけど。 「*a と a[0] は同じ」あるいは「a と &a[0] は同じ」と言いたかったのかな? a の型はあくまで配列型、つまりこの場合は char[3] という型を持つ。 ただし配列が式中に現れた場合には配列の先頭要素を指すポインタに型変換するという規則によって a と書いたら型 char* の値として解釈される。 先頭要素を指していることになるので a==&a[0] が満たされる。 で、この a[0] という表記もクセモノで、定義上はポインタ演算の構文糖であるという扱いになっている。 a[0] とは *(a+0) のこと。 &a[0] は &*(a+0) と同じということになるんだが、 演算子 & のオペランドが * の適用結果であるときはどちらの適用も無かったことになるというルールがあるので &*(a+0) から &* は消去されて a+0 が残り、 0 を足しても結果は変わらないからこれも消去すると a が残る。 故に &a[0] == a VisualStudioでWin32APIの入門したいんですが どのプロジェクトテンプレートを使えば良いのでしょうか? if elseから学びたいのですが、余計な習っていない文がついたサイトばかり出てきます。 どこを見ればいいのでしょうか 今、リファレンスなんてまともなの売ってない 頼んでもいない文が山盛りついていて、一からやりたい奴は苦労している とほほのhtmlみたいなのは売ってないんだよ つまりリファレンス足り得てない本ばっか いま、プログラムを始めるのは独学では不可能と言ってもいい 分かりづらい言い方しなければ、今はif elseから始める本は売ってない 紙のリファレンスを読むという発想で生き残れるとは思えない。そこはもうデジタルファイルかウェブだよ。 君等の政府を見てみよ。教科書すらデジタル化できない。日本語入力の標準化すらままならない。紙ベース、電話ベースの考えなんかデジタル化で吹っ飛ぶ時代なんだ。 >>95 これをどう初心者が読むんだ???読めないよ 基本的な構文はこうします、ああします、がなにもない 簡素な実例を使って一個づつ説明しないんじゃ、初心者は誰も読めん たとえば、C言語のprintf関数を見たいのであればC++のstd::printfを参照しないといけない。 elseをさもなくば、とか訳すのな、それは合ってる しかし n>10とかifに入ってたのなら初心者には、さもなくばではなく 10より小さければ、という意味になります。と書かんといかん。 なんだかねえ、わざとやってんのか 全てを伝えづともそれくらい書かないとダメだろと言いたい >>98 そんなことはない。 C 由来の関数は C++ の規格では C の規格を参照していて、詳細は C の規格を見ないと書いてない。 C と C++ は付かず離れず平行して存続すると D&E でも言及されている。 だいたい C のほとんどの関数はそのまま使うには C++ では行儀が悪いことが多いだろ。 互換性の都合で仕方なく入ってるだけで、 C++ に取り込みたくなんてないと思う。 入門書というのは必ずしも簡単ではないということは知っておいて欲しい。 その分野でまず必要な知識を書いてあるのが入門書というもので、専門書の一種には違いないわけで。 ハードルを下げようと思えばいくらでも下げられるし、 実際に絵本に毛の生えたような説明の仕方をしているものもあるのだけれど、 きちんとした知識にするにはそれなりに難解な部分だって最終的には避けられない。 入門書なのに難しすぎる! と思うこともあるかもしれないけど、実際にそれは入門に必要なんだってば。 そんな難解な教え方している専門学校ですらどこにもない アスキーとかナツメとか技術評論社あたりを当たると入門書が見つかると思うぜ。 害虫がまた初心者向けに少しでもなるようなページを検索結果から消しているな >>38 秋月のPIC用c使ってるけどこれ規格準拠する気更々ないよな、cっぽいナニカ まあアマチュア向けで気にすることも無いと思うけど するとPCスマホ組み込みサポート網羅すべく頑張ってるc規格が可哀想に思えてくる… スタック数段のマイナーマイコンcだと関数スコープから呼べない標準関数があったりしたな 何段消費するか明示して欲しい まさかテストケースをグローバルで書いてるわけないよな 徹底的に呼び出し避けたマクロライブラリも挙動不審になりがちだしあきらめよう >>66 #defineでは書けなかった でもif文で処理を分ければ最適化で通らない処理とif文の処理は削除される int a=1; if((char)a==0) { ; } else { ; } こんな感じ 間違えた int a=1; if(*((char *)&a)==0) { ; } else { ; } こんな感じ ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる