前スレのこれに質問です。
32bitアプリだとmallocで確保していくと2GB近くでエラーになりませんか?
頑張って色々施しても4GB近くが32bitだと限界じゃないんですかね?
もし回避策があるなら教えてください。
999デフォルトの名無しさん (ワッチョイ 7f36-///2)2020/01/14(火) 19:45:37.22ID:MAaOflfD0
>>978
ちょっと待てや
おまえ単一仮想記憶を前提に話してるか?
今や多重仮想記憶が当たり前で単一仮想記憶はかなり特殊な存在だぞ paeのことかしら。それでもアプリが使えるメモリは4gb以下に制限されるみたいだけど
アドレスを保持する変数が32bitなんだから
どう頑張っても4GBまで
実際は32bit Windowsの制約で2GBまで
あとは前スレ >>982 の方法しかない しかし別プロセスにしようとどうしようと
結局データのアドレスは受けないといけないので
そのポインタ自体が32bitで管理されてる以上
その限界はどうしようもないような。
>>8
セグメントレジスタとセットで48bitで処理するって意味
(書かなきゃわからないですか?)
CPU的には可能だけどOS的にもコンパイラ的にも不可能だから実質不可能 32ビットだと大きいメモリは最初の方で確保して最後の方で解放するなぁ
あるいはプロセスを分けるか
>>10-11
ではお聞きいたしますが、セグメントレジスタ16ビット+レジスタ32ビットのペアで指定した先は何ビット空間ですか?
IA-32 アーキであるかぎり、どうあがいても32bit 空間ではないでしょうか?PAE 搭載であってもユーザーからみえるのはやっぱり32ビットなのでは? 多重仮想記憶ってプロセス毎に同じアドレス空間を提供するだけの話
(逆に単一仮想記憶はプロセッサのアドレス空間を分割してプロセスに提供する)
http://yougo.ascii.jp/caltar/多重仮想記憶
前スレの質問はアプリの話だからあんまり関係ないよ
オーバープロセスとか言うオレオレ用語はよくわからんけど…
オーバーコミットの話じゃないよね? >>14
私の質問に回答できないのですね…
IA-32 では、それが PAE を搭載していたとしても、ユーザーが一度に扱えるのは32ビットどまりですよ
>>10
>CPU的には可能だけど
CPU的にも不可能です windows依存なら CreateFileMapping MapViewOfFile で32ビットより大きいのをやりくり
今、話題になっているのは32bitOSの場合であって、IA-32 どうこうは微妙に違う話にも思えるのは内緒。
ということで話を戻すと、例えば32bit版Windowsには、OS管理外メモリとして8Gだの16Gだの扱うことができるRAM-DISKアプリがあるわけで。
32bitアプリでも、セグメントレジスタに正しいセレクタ値をセットできるのであれば、4G超のメモリ空間を扱える、と言えなくもない予感がする。
386の時代から仮想アドレス空間は64TBだってのに
>>18
RAM-DISK使わんでもAPIには上位32ビット下位32ビットの64ビット指定できるから 話の前提は、64bitOSで32bitプログラムを動作させる場合ですね。
できるならやり方を具体的に提示してくれよ
罵り合ってる内容が一切質問者に有益な情報じゃない
64bitOSなら32bitアプリで4GiBまで扱える(ように出来る)
これでいくらかは改善するのでは?
>>23
確かにオプション指定でそれが出来ますね。
やっぱりそれが限界でしょうかね。 それでもダメなら
DLLを扱う用の32bitプロセスと
多量のメモリを扱う64bitプロセスに分けて
プロセス間通信でデータをやり取りする
>>19
80386 に関していえば、その記述「386の時代から仮想アドレス空間は64TB」はわりとデマ的に流布されていることは理解します。手元の本
https://www.あまぞん.co.jp/dp/4756101305/
にも載っていました、確かに紛らわしい記述だとは思います
セグメントレジスタが指す「セレクタ値」は8バイトごとである、という事実から、セレクタ値のアドレスを意味する部分を16-2=14ビットとして、これと一般レジスタ32ビットとの直積から
46ビット=64T 分のアドレス空間が取れる、という計算だとは思いますが、この記述は不正確であり実情からは程遠いと思います
80386 では、セグメントレジスタが指すセレクタ値にひも付けられているセグメントベースはやはり32ビット空間の中なんです。32ビット空間の外に出ることはありません。 Pentium Pro の時代から64GiB扱えるわけですが
Windows Server系は32bitでも64GiB使える(ものもある)わけですが
問題はフラグメントなのでアドレス空間が広がれば解決するわけですが
>>29
セグメントレジスタが指すグローバルディスクリプタテーブル(GDT)中の一つ一つのエントリー(セレクタ値)に含まれる情報の配置状況が 80386 から変わっておれば、あなたのおっしゃることは理解できます
pentium を例にそれを示せますか? >>6
ググっても出てこないので、正確な技術用語を教えてください 大きいメモリをできるだけ上位のアドレスで割り当てる
普通のメモリ割り当てなら下位のアドレスになるから
使い分けで断片化の影響を減らせる
VirtualAllocの MEM_TOP_DOWN
XPで付属のIMEだかuxtheme.dllあたりが中途半端なbaseaddress指定してあって1ブロックとしては700MBくらいまでしか確保できなかった思い出
2つスレッドがあってサブの方を使わない時は
こんな感じで待機してるんだけどやっぱマヌケかな?w
その都度作った方がやっぱいいの?
while(flag){ Sleep(1000); }
間抜けというか、完全に寝かせてしまえばいいのでは?
>>38
環境を書かないと
WindowsならDefWindowProc呼び出すとか
Unixならselectでイベント発生を待っているとか >>38
それは簡単のように見えて、実は奥深いプログラミングのテーマの1つかもだけど。
問題がないのであれば、そのコードはマヌケでもないし悪くもないので、そのままでいいと思うよ。 >>39-41
環境はWindowsです。
スレッドは二つだけでサブも結構使ってるので
flagで管理して動かしたい時だけTRUEにしてる感じです。
特に動作に問題はないのでこのままでいいんでしょうかね。 リソースの競合がないんなら好きにすればいいけど、
あるなら、動いているように見えて低い確率で破綻するってのもあるよ
>>42
問題がない以上、NGにする理由もないわけで、このままでいいです。
言い換えると、何か問題があるなら、それに応じた修正や変更の必要ありかもです。 >>43
一応そのへんは気を付けてるつもりなので今のところは問題ないですね。
>>44
分かりやすくていいので問題ないならこのまま行こうと思います。
ありがとうございました。 呼んでから起きるまでのタイムロスはどうでもいいのか
>>46
そこはOKです。瞬時に処理してくれなくても問題ない処理なので。 >>38
イベント待ちがスマートでは?
サブは WaitForSingleObject でイベント待ち
サブを動かす時は メインスレッドから SetEvent する >>38
すげーマヌケに見える
スレッド作成する時間も惜しいなら>>48が言うようにイベントとかを使うべきだし、そうでないなら自分で言ってる通りその都度作った方がいい
そもそもサブともうひとつのスレッドとのやり取りはないんか? スレッドプール用のapiあるんだからそっちのが良くない?
POSIXスレッドなら cond wait みたいなの使うのがよさげ
int main()
{
int array[100][10];
array[0][0] = 61;
printf("%d\n", *(int*)array ) ;
}
これなんでIntポインターにキャストしないとだめなん?
arrayでもポインターだから*つければ配列の先頭参照できないとおかしくね?
例えば
char array[] ="unko king";
だとしたら
%s とarrayで文字列表示できるじゃん
*(char*)arrayなんてしないでしょ?
%s とarrayで文字列表示できるじゃん
*(char*)arrayなんてしないでしょ?
じゃなくて(char*)arrayだわ
みすった
>>56
添字つけない場合は配列の先頭のメモリアドレスを持つポインタなんだがw >>56
例えば
int array[40][40];
array[30][30]=10;
int *p;
p=array;
*(p+(40*30)+30)でarray[30][30]にアクセスできる 型に互換性があることと、型が同じであることは異なる。int[20][20]はint*とは互換性がない。
配列はアドレス値を動かせない。
配列とポインタではsizeofの値が違うことがある。
多重ポインタと多次元配列はメモリレイアウトが異なる。
よって配列はポインタではない。
2次元配列は各行の配列が配置されてるメモリ上のアドレスのリストですか?
その場合、そのリストの要素であるアドレス値はどうやって取り出せますか?
この場合で言う、データの列の10,20,30というようなアドレス値を取り出す方法はありますか?
1つの配列は連続した1つのメモリブロックになっている。二次元配列も1つのメモリブロック。配列の中身は実体。
配列名のみを指定すると配列の先頭へのポインタと互換になる。
int array[10][2]はint[10]が2個あるという意味ですか?
ではそのint[10]というのを行と呼ぶとした時、なぜこの実行結果では行間のアドレス間隔が行数になるのでしょうか。
>>54
おまえさんが array[0][0] = 61; と書いているように、
int は array[0][0] だ、ここ大事だぞ
array[0] は int ではないことを絶対に忘れるな
知ってのとおり
printf("%p", array); は
printf("%p", &array[0]); と解釈される
つまり int でないもののアドレスとなる
だから
printf("%d", *array); と実体化すると
printf("%d", *&array[0]); のように int でないものとなる int three[2][3][4];
これは4の配列が3個で、それが2個ということでおk?
そうじゃない
int [3] [4]が二個
って考える
そのあとint[3][4]について考えると
int[4]が3個ってなる
静的に確保された多次元配列の実態はただの1次元配列だから
int array[2][2] = {};
array[1][0] = 2525;
printf(“%d\n”, array[0][2]);
ってやると2525が出力される
再帰むずすぎてハゲそうだわ
これなにやってるかパット見て分かる人いる?
int rec(int num) {
printf("%d\n", num);
if (num == 1)
return 1;
else {
return num * rec(num - 1);
}
}
再帰の例で一番出てくるヤツ
if の中はゼロとの比較の方が良いと思う
rec(1) = 1
rec(n) = n * rec(n-1)
漸化式による記述
>>78
rec(3) 位にして自分でトレースしてみればわかると思う 再帰のコードを書いていて不思議な気分になるのは
なんで今書いているものを呼び出せるんだろうとか思っちゃうからかな
単純なループですむならその方がいいだろうな。
木構造の探索みたく本質的に再帰で書いた方が自然なものは再帰のがいい。
今時〜が遅いと言い放てる環境ならまず今時Cを使う意味がない
再帰でなければ実現できないアルゴリズムがあるとすれば,例えばどんなの?
> でなければ実現できない
という要件が気になる。
迷路のルート検索に再帰で書いた事あるけど10000ぐらいでスタックオーバーするので再帰をループで書き直した思いで
お前ら知ってるか
Pythonの構文解析はgoto文の状態遷移なんだぜ
あれ見てPythonは業が深い言語だと思ったわ
まぁあれが一番早いんだろうけど
ツリー探索なんか待ち行列を使えば非再帰に変形できるからな
C言語で記述可能かどうかって意味なら
どんなものでも非再帰に変形可能
>>95
構文解析とかは大抵そうだよ
最近は使ってないから変わってるかも知れんが昔yacc/lex使った時の出力はgoto使い捲くりだったし >>85
関数の最初に「返り値と関数名と仮引数リスト」を書くでしょ。
それだけの情報があれば関数を呼び出すには十分なのだ。
…と、構造体名の前方宣言みたいな説明でケムに巻いてみる。 ソースコード上ではあたかも再帰が可能かのように見せかけてるだけでしょ
そういうウソをコンパイラは演出してくれている
>>85
実際に再帰呼び出しが実行されるのはその関数が書き終わったあとなのだから何の不思議もないような気がするが。 そもそもC言語の再帰をコンパイルして出てきたマシーンコードって
スタックに積んでgotoしてるだけのループじゃん
本物の再帰を実現できる無限のメモリーなんて存在しないじゃん
だから現状は擬似再帰、
しかもあと500年くらいは擬似再帰で我慢してもらうしかない
再帰は再帰専用のメモリースペースを使うから限界がすぐくるだけやぞ
今の科学力では本物の数学的な再帰なんて実現出来ない、
だから、擬似再帰に留まってる
あとは実数マシンと整数マシンで、現状は離散的な整数マシン
実数をそのまま扱えるマシンすら存在してない
コンピューターに限界がある
なんてことは誰でも知ってるから
いちいち書かなくても良いよ
だな
>>102が言うからには他の言語ではもっと画期的な方法があるのかと思ってた >>105
「アナログコンピュータ」ってのがあって、俺がいじったのは
その都度回路を組んで信号を送って電圧計の針の振れを観察するんだが、
あれは一応、物理の限界の精度で実数をそのまま扱うマシンだね。
このスレッドで扱う対象じゃないけど。 アナログと実数には遠い溝が...
精度はデジタルの方がはるかに上
>>54
そんなキャストはしてはいけない
お前の使い方が間違ってる
敢えて括弧を付けるが正しいのはこの二つだけ
printf("%d\n", *(array[0]));
printf("%d\n", *(*array)); 無駄なだけの「正しい」括弧なんかやめれ
printf("%d", (*array)[0]); //少なくともこれの意味がわかるようになるまでは
丸括弧の次に優先順位が高い角括弧ってだけの話じゃん
識別子に最優先くっついてガツンと先に作用するて意味じゃわかりやすい関数等の丸括弧を除いて最強という。
>>117
なんか演算子の優先順位をいい加減に覚えてそう。C言語のBNFでも見てきたら? + と << が混ざった演算
( ) を付けないと警告を出すアホコンパイラがあるんだよね
x86はアラインメント不整合でも正常に読み書き出来る
AVXレジスタで
アラインメントが整ってないと使えない命令があるから
それを使えば例外発生する
MOVAPS など
int main(void)
{
return *(int *)0;
}
の方が簡単
>>123
それセグメンテーションフォルトでは?バスエラーになるCPUあるの? リードアクセスだしなあ
0番地が未実装というのは考えにくいね
そもそもバスエラーとかセグメンテーションフォールトは、CPUの例外等をOS側で適当にマッピングして、そう呼ぶOSがあるというだけだからOS依存。
x86/x64のCPUで>>123のような適当なメモリアクセスを行うと、CPUで例外#GPや例外#PFが発生する。UNIXならそれを状況に応じてセグメンテーションフォールト(SIGSEGV)やバスエラー(SIGBUS)として扱い、WindowsだったらEXCEPTION_ACCESS_VIOLATIONとして扱う。
アライメントがずれている時は、発生した例外#ACをバスエラー(SIGBUS)やEXCEPTION_DATATYPE_MISALIGNMENTとして扱う。 ASを出してから一定時間経過してもDTACKが帰ってこないとBERR端子をぶっ叩かれてバスエラー
68K通った人からするとアライメント不整合はアドレスエラーの印象が強い
スパッと例外で死んでくれれば良いんだけど
単にズレるだけってCPUがある
int i;
int *pi = &i;
*((int *) (((char *) pi) ÷ 1)) = 1;
x86はこれがバスエラーにならないね
>>130
÷は+だとして、
eflagsのACビットを立てておくとバスエラーになる そもそもx86だとバスエラー発生が無理なんではないのか?
>>129
ARMのCPUでアラインメントの整合を怠ったら
偶数番地/奇数番地か、その2倍のアドレス値だったか
データの半分しか書き込まれなくて…って事態を目撃したことがある。
素朴なビットマップグラフィックのプログラムだったので
画面がシマシマになるのが文字通り目で見えた。
同じソースをx86系で実行すると期待通りの結果になるんだよ。 >>130
>>133
// x64 linux
volatile int x[2];
int main () {
asm("pushf");
asm("btsl $18, (%rsp)"); // set AC
asm("popf");
// *(int*)((char*)x+1)=1; // SIGBUS
asm("pushf");
asm("btrl $18, (%rsp)"); // clear AC
asm("popf");
return 0;
} >>135
130です
130のように書くとバスエラーがなければ ip を破壊する可能性が高いし、最適化でコードが生成されないためのケアもされていて思慮深いコードですね…
しかしGASのオベランドは逆に見えてしまって… やはりアセンブラの領域にまで踏み込まないと無理なんでしょうね