C言語相談室(上級者専用)

■ このスレッドは過去ログ倉庫に格納されています
2018/03/02(金) 22:48:03.65ID:2Cs+DkMh0
C言語の話題のみ取り扱います。C++の話題はC++スレへ。
上級者専用です。10,000行程度のソースを扱えない人は以下スレへ。

C言語なら俺に聞け
https://mevius.5ch.net/test/read.cgi/tech/1519046038/

適宜以下を使用してください。
https://paiza.io/
https://ideone.com/
http://codepad.org/

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

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

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

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

次スレを立てる時は本文の1行目に以下を追加して下さい。
!extend:on:vvvvv:1000:512
VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured
2018/08/05(日) 00:50:03.59ID:fZk3Cg460
すまん。途中で送信してしまった。
そうするとコンパイラにmain()の型はintだと怒られた。
2018/08/05(日) 01:34:55.28ID:/g7t90jda
型がintというのは決まってる。
実際の範囲は実装依存。windowsだと違ってなかったか?
66デフォルトの名無しさん (ワッチョイ a39f-Xflc)
垢版 |
2018/08/05(日) 07:12:37.38ID:cdvogGHQ0
main()が戻す値は呼び出す側の問題だとは思うが、その部分(crt0とか)は普通はC言語に合わせてintを
返してくると想定して作られていると思う。しかしその部分まで自作するというのであればなんでもアリではある。
https://en.wikipedia.org/wiki/Crt0
2018/08/05(日) 08:37:27.73ID:5+7WSxVZ0
シェルが受け入れるコマンドの終了ステータスの値が0-255の範囲、
てのはUNIX系もDOS系も(珍しく)一致してるのね。
unsigned char の外に出ないことは間違いないわね。

ANSI以前の古いCでの「宣言なしに使われた外部関数はintの値を返す」
という仕様が、規格化したときに互換性の問題を生まないように
main()の返り値はintと決めたんじゃないかしら。
2018/08/05(日) 12:29:08.02ID:fZk3Cg460
なるほど。まあ過去互換性は重要だしね。
ただ,CはPOSIXというOSの標準規格を定めてる団体が関与して設計されてるから「リターンコードは0--255。よってmain関数の型はuint8_t」と割り切ってくれてもいいのになぁ。
とか勝手に思ったりしてる。
2018/08/05(日) 13:13:57.79ID:/g7t90jda
まあintが妥当だろう。
しかし、_exit()に渡すのがintでwait()した時も一応exit statusはintだよな。
どこで上位ビット欠落させてんだ?
70デフォルトの名無しさん (ワッチョイ a39f-Xflc)
垢版 |
2018/08/05(日) 18:30:06.69ID:cdvogGHQ0
>>69
OSの中だ。_exit() はシステムコールだし。
まあでも UNIX 系 OS じゃないならこれは違っているかも知れない。
2018/08/06(月) 01:15:24.28ID:/d0+B2Ty0
ちょっとCの範疇を越えた話になるけど
リターンコードが0--255ってどういう段階で決定されたんだろう。
DOSとUnixが同じ範囲のリターンコードを持ってるって、偶然とは考えがたいんだけども
2018/08/06(月) 02:07:20.39ID:xc/1a6k50
unix等の先行者を参考にDOSを作ったんだから
2018/08/06(月) 07:45:24.26ID:1aQ1rnwf0
DOSの終了ステータスはUNIXの仕様をそのまま使用だと思う。

UNIXの方は、子プロセスを作って別の仕事をさせるって定型処理で、
「親プロセスで子プロセスの終了を待つ」ためのwait()系の関数が、
・子プロセスが正常終了した場合は子プロセスの終了ステータス
・子プロセスが割込みで中断された場合は割込みの種類
という2つの情報を1個の返り値で戻すことと関係あるのじゃないかな。

1個の整数値を上位と下位のビット群に分けて別の情報として使うために
それぞれの情報量を1バイトずつに制限した、と。
2018/08/06(月) 08:23:05.65ID:jTWGCXc00
UNIX板のおじさんに聞いてみたら
2018/08/26(日) 08:24:46.45ID:dLFVucRz0
auto変数で char配列を可変長で動的に確保する方法は無いかな。
アセンブラレベルならスタックポインタを操作すれば可能だと思うが。
文字列処理の内部バッファとして入力に合わせたサイズを確保したいんだが、とりあえず今は固定長バッファとそれを超える場合は malloc でやってる。
2018/08/26(日) 09:09:31.40ID:Vxoswi+gd
alloca
2018/08/26(日) 09:18:39.26ID:O9adGcKd0
>>75
gcc使うなりalloc()使うなりすればいい
とりあえず
vla c言語
で、ぐぐれ
2018/08/26(日) 09:29:28.31ID:ik1BtrwR0
>>75
alloca
標準ではないけどほぼ標準扱い。(殆どの環境で使える)
ただし realloca は無いので注意。
2018/08/26(日) 09:31:08.30ID:dLFVucRz0
>>76-77
ありがとう、まさにぴったり。
言語レベルでの可変長配列は C11 から(オプションだけど)入ってるんだね。
90年代からメンテされてるコードだからそっちは使えなそうだけど、alloca を検討してみる。
2018/08/26(日) 10:56:05.32ID:O9adGcKd0
>>79
環境わからんからなんとも言えんが組込みとかWindowsとか意外にスタックサイズがしょぼい環境あるから気を付けてね
2018/08/26(日) 11:49:56.37ID:hQMrm9ZNa
いやいや、C99からだよ。C11でオプションになった。答える方はそのくらい知っとけよ。
まあ入力が小さいのが予め分かってないと使いにくい機能だよ。
2018/08/26(日) 13:04:10.92ID:HHP/3bjy0
>>75
その入力というのがファイルからの1行入力みたいなものならば getline() 使ってしまえば
自分で考える必要がなくて楽だ。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/getline.3.html
2018/08/26(日) 15:51:52.71ID:0Dyu3Dip0
発端の >>75 の意図次第だが、free()しなくても安全に蒸発して欲しいとか、
ヒープの確保と解放の処理時間を嫌っての話ならgetline()はちょいと違うね。
文字数の予測が難しい入力を扱うにはとても便利なんだけど。

それにしても「上級者専用」って看板が架かってることを意識すると
このスレッドは書き込みにくいな。気後れしちゃう。
84デフォルトの名無しさん (ワッチョイ ed68-DNis)
垢版 |
2018/08/26(日) 16:14:52.46ID:tQPCeAJ90
alloca
2018/08/26(日) 16:21:37.62ID:hQMrm9ZNa
動的確保が無難なんだよね。最後にfreeすればいいだけだし。
最近まで知らなかったんだけどscanfで%msで動的確保してくれるの便利だな。scanf自体はなかなか難しくて使いづらいが…
2018/08/26(日) 17:31:54.88ID:dLFVucRz0
>>81
あ、C99で入ったのをC11でオプショナルに格下げ(?)されたってことか。
処理系によっては厳しい実装なのかな。

やりたいことってのは文字列のエスケープを含んだ組み立てなんだけど、使用するエスケープ関数がありものでその仕様は入力文字列長に対して2倍以上の出力バッファを与えないといけないことになってる(出力サイズを指定して打ち切らせることができない)。
実際に2倍に膨らむことは稀だし、エスケープするのも文字列中の一部なので、自分の処理で最終的に出す出力結果は論理最大よりかなり小さくなる(自分の処理は指定された出力長で打ち切る)。
まず来ることが無い事態のために論理最大の配列を取っておくのもどうかと思い、いい方法があるかここで相談させてもらった。
しかし想定外のことが起きちゃった時にどうなるべきかを考えてどうするかを決めるから、もしかしたら動的配列の意義が無くなって別の方法にするかもしれない。
この処理自体は高頻度で呼ばれるから、高速で省メモリそして内部的な都合での打ち切りは極力避けた作りにしたいって感じ。

いろいろコメントありがとう
87デフォルトの名無しさん (ワッチョイ ed68-DNis)
垢版 |
2018/08/26(日) 17:43:02.62ID:tQPCeAJ90
あらかじめプールしておいて使いまわす
足りない時だけ臨時で増やす
2018/08/26(日) 18:09:50.26ID:Vxoswi+gd
ReactOSというOSでフォントエンジンの改良を行っているが、
Google Chromeというブラウザでおかしくなる。
何故かEIPレジスタがゼロになって、初回例外が発生する。KDBという付属のデバッガでトレースしたが、
どこの関数で例外が発生しているかわからない。
たすけて。。。
2018/08/26(日) 18:15:57.28ID:Vxoswi+gd
これがイシュー。
https://jira.reactos.org/browse/CORE-14926

これが問題のコミット。
https://github.com/reactos/reactos/commit/35f62fc5ba0b69e7335ff41400cb3b45660f4557
2018/08/26(日) 18:22:22.54ID:Vxoswi+gd
晒しあげ
2018/08/26(日) 18:39:01.79ID:Vxoswi+gd
スタック破壊の可能性か。。。
2018/08/26(日) 19:04:13.59ID:ik1BtrwR0
>>85
> 動的確保が無難なんだよね。最後にfreeすればいいだけだし。
結局の所、結論としてはそうだね。

>>86
多分素直にmallocする関数をラップして使う方がいい。

仕様の動向自体は知らんが、
> 処理系によっては厳しい実装なのかな。
技術的にはこれはない。alloca相当(ポインタ相当)にすればいいだけなので。
ただ、間接アクセスになるから速度は落ちるし、
mallocに対しての利点は『自分で』freeしなくて済むことくらいしかない。
(『自分で』ソースに書かなくてよくなるだけで、速度上のメリットはない。
reallocaが無い為、最初のバッファ(=サイズが不明)はヒープ上に動的確保するしかなく、
自分で書いてなくてもどこかでfreeされてるだけだから。なら最初からgetlineでもいいし)

ただ、そちらの実装は(おそらくバッファオーバラン対策で)一旦固定長バッファに取り込み、
その後alloca領域に対してのコピーか?
ならまあ一応freeしなくていい速度上のメリットは残るが、
一般的にはスタックサイズ管理のコストが増える方が問題とされ、その実装はないとも思うが。

結局、allocaもイマイチなんだよ。だから標準にもなりきれない。
2018/08/26(日) 19:12:21.53ID:ik1BtrwR0
>>83
>>1,13読んで以下にどうぞ。
C言語なら俺に聞け
https://mevius.5ch.net/test/read.cgi/tech/1534430162/

>>12
>>89
それがこのスレの正しい使い方かもしれんね。
ぱっと見て分かるものでもないけどさ。
2018/08/26(日) 19:20:25.22ID:uLlG7vHAa
allocaとか動的サイズ指定の配列はスタックだから基本的にはmallocするよりは速いよ。頑張っても同等。
繰り返して呼ぶなら差が出るかもね。
2018/08/26(日) 19:53:34.99ID:ik1BtrwR0
ああ、言い直しておくよ。
allocaとmallocなら、

確保:allocaの方が速い
使用:同速(ただし初回からキャッシュが当たる分allocaの方が速い)
解放:freeの必要が無い分、allocaの方が速い
 (ただし実装によっては上位でfreeしてるだけであり、同速)
管理:通常、ヒープサイズ>>>>>>スタックサイズの為、サイズ管理が必要

速度差が見えるような使い方が出来るのなら、ある意味大したもんだと思うよ。
2018/08/26(日) 20:17:14.11ID:iSNBdVUGa
スタックって確かスレッド毎に肥大化してくよね?
で、肥大化してもスレッドが停止するまで縮小しない

あってる?
2018/08/26(日) 20:19:54.25ID:r4V1HxTD0
関数から戻るとき(エピローグ)にスタックは縮小することがある。
2018/08/26(日) 20:26:06.20ID:Vxoswi+gd
実際のx86 CPUでスタックポインタを表しているのが、ESPレジスタの値。スタックサイズの増減はESPの書き換えに過ぎない。
2018/08/26(日) 20:30:48.56ID:dLFVucRz0
流れのついでに聞いてみたいけど、malloc はスレッドセーフでしょ。
てことは内部で排他をかけてると思うけど、となるとマルチスレッド下で malloc や free を多発させるとパフォーマンス的に良くなかったりしないかな。
言ってなくてごめんだけど、今回の処理はマルチスレッドで動くんだ。
なのでバッファはスタック上に取れると都合がいいという事情もあるし、特別な初期化手順や終了手順も用意したくないから事前に malloc して使い回すってのもやりづらい。

ちなみに動作環境は x86 linux だから、alloca は SP をズラすだけの非常に高速な実装になってるんじゃないかと想像してるから、関心は高い。
でも、最悪でもスタック上に収まるバッファという前提にするなら最初から論理最大サイズ固定のバッファで良くね?なんて話もあるから、実際にどうするかはこれから検討。
2018/08/26(日) 20:39:55.03ID:QMrmo6TZM
glibcのmallocならサブarenaから獲得してくるから性能問題にはならないらしい
101デフォルトの名無しさん (ファミワイ FF49-DNis)
垢版 |
2018/08/26(日) 21:03:16.49ID:KvfxyzVvF
そうだよ
条件後出しω
2018/08/26(日) 21:06:39.43ID:ik1BtrwR0
>>99
サイズの問題がないのならallocaを使うことに問題はない。
mallocより遅くなる理由もないので。

ただ、普通に組めば分かるが、
> malloc や free を多発させる
ってのがあり得ない。
仮にこれがallocaで有効に代用出来るとするなら、再帰下降パーサ等、「再帰」が必要になるが、
再帰下降パーサの場合はインミュータブルでよく、元の文書をオフセット付きで参考して終わりだ。
再びallocaすることはない。
同様に、ループでパースするのなら、ループの外でmallocして十分な領域を確保し、
そこに上書きで使うことになる。だからmalloc/freeは1回ずつで済む。

もう一度言うが、allocaはスタックだから、「再帰」しないと領域を追加出来ない。
この使い方は普通無いし、君もやって無いと思うよ。
でも、普通のmallocを全部allocaで代用しても、サイズ以外の問題は無いから、可能ならそれでもいい。
2018/08/26(日) 21:08:26.06ID:ik1BtrwR0
> alloca は SP をズラすだけの非常に高速な実装になってるんじゃないかと想像してるから
これはその通り。

> 最初から論理最大サイズ固定のバッファで良くね?
これもその通り。上記ループなら普通これで行く。
それがスタック上で問題になるサイズならmalloc/freeが1回ずつ必要になる。
だから君の今の実装>>75もさほど悪いわけでもない。

今風の「実装を外に漏らさない」方針なら子関数でmalloc/freeやallocaすることになる。
おそらくそれで考えているのだと思うが、元々のCの思想はそれとは違い、

char* buff = (char*)malloc( ... ); // または char buff[2048]; 等
while (....) {
parse_func(buff, .... );
}
free(buff);

として外側で確保し、それをparse_funcに渡す。
これにより、変数の寿命とスタックの動作を一致させ、freeし忘れもなくなる。
この方法だと、allocaで毎回「SP をズラすだけ」すらする必要なく、parse_func内は最速になる。
(allocaを毎回繰り返すよりも速い)
2018/08/26(日) 21:12:44.54ID:uLlG7vHAa
あくまで処理系依存の話として…
マルチスレッド固有の問題はほぼない気がしますね。malloc/freeは単に別の領域確保していくだけだしスタックの場合はスレッド生成時に確保すると。
で、まあmallocの実装はそこまで悪くないと思うけどスタックが速いし、さらに静的領域の方がちょっと命令数は少なくなるでしょう。
2018/08/26(日) 21:36:27.43ID:dLFVucRz0
>>102-103
いろいろありがとう。材料は揃ってると思うので、最終的にどうするかはこれから決めるよ。

>>104
malloc は内部的にはヒープから領域を切り出してくるわけで、切り出したチャンクは恐らくリンクかなにかで管理してるはずでしょ。
これはプロセス単位で一式だから、マルチスレッドでよってたかってこの構造を更新するには排他は欠かせないと思うんだがどうなんだろ?
切り出されたメモリがマルチスレッド下でどうかという話ではなく。
>>100 の内容はちょっと分からないから調べてくるが、結局は誰かが排他してるんじゃないのかな。
2018/08/26(日) 21:52:41.59ID:QMrmo6TZM
>>96
実行環境依存だが、win/linuxならその認識で良い
allocaは便利だがスタックの肥大化を加速させるので
環境によっては注意が必要

>>105
興味があれば
https://youtu.be/0-vWT-t0UHg
2018/08/26(日) 22:03:50.42ID:r4V1HxTD0
>>97-98 間違いです。すみません。
2018/08/26(日) 22:07:11.30ID:ik1BtrwR0
>>105
以下読め。マルチスレッドに関する疑問点については全部書いてあるから。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/malloc.3.html
2018/08/26(日) 22:08:38.19ID:uLlG7vHAa
>>105
ナイーブなmallocの実装はそうです。中央集権的。同時に動くのは1個だけ。でもクリティカルセクションはそんなに広くないかも?
まあ実装はいろいろあります。
2018/08/26(日) 23:49:28.30ID:dLFVucRz0
>>106
すげーおもしろかった!
マルチスレッドでどうやってるかについても分かったよ。
過渡期の性能を犠牲にして使っていくうちにいい状態に収束するようにしてるのね。
しかし malloc のコードが 5000行てw
ただ、mmap すればメモリ管理のコストが小さい的な言いぶりはどうかなって気はするな、動画の中でもツッコミ入ってるっぽいけど。
結局カーネルだって何らかの形でアドレス空間の空きを検索するし、アドレス空間を割り当てる処理にしても排他はかけてるはずだから、それなりのコストはかかるし競合の問題もあるよね(ユーザーがやる処理よりも高効率だろうと思うけど)。

>>105
malloc の話を持ち出したのは、排他とかで結構遅いんじゃね?ってのが出発点なので、
排他はしてるって言うし mmap だからという説明じゃ解決って話でもないかなって感じ。

>>109
>>75 の頃の時点では K&R アロケータ程度の認識だったからマルチスレッド下ですげー遅そうな印象だったけど、さすがによく考えられているということは分かったよ。


ちなみにこれも読み始めてた。
https://www.valinux.co.jp/technologylibrary/document/linux/malloc0001/
>>106 の動画を見てだいぶ見通しがよくなった。
2018/08/27(月) 00:24:32.33ID:+HD/yYG+0
>>63
5.1.2.2.1
2018/08/27(月) 04:36:47.89ID:y2YT/eYl0
>>111
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=24
ここか
2018/08/28(火) 10:01:58.54ID:AJzSIbICa
>>106
サンクス
2018/09/01(土) 15:23:05.79ID:Z9gelboG0
POSIX準拠を念頭にC言語を書かれている方に訊きたいのですが、機能検査マクロって実際どのように使われていますか
#define _POSIX_C_SOURCE 200112L
#define _XOPEN_SOURCE 600
↑僕はこのくらいであればシステム互換性は担保されると思ってるんだけど
未だにPOSIX 1998にしか対応してないOSやコンパイラとかあるんですかね。
少なくとも_XOPEN_SOURCEが600以上じゃないと<math.h>においてM_PI定数が扱えないので
数式処理のプログラムをよく書く身としてはちょっと困るんですけども……。
2018/09/01(土) 15:25:50.73ID:AtDk99X7d
>>89
解決。ヌル文字忘れ。
2018/09/01(土) 16:42:41.27ID:PErE712pa
好きな人が古い環境を使っているという事情でもなければ、単に無視すれば良いのでは
2018/09/01(土) 16:56:39.73ID:AtDk99X7d
>>114
CMakeで環境を判定して、マクロを定義するのが王道だと思う。
2018/09/01(土) 18:20:25.47ID:vZp6TokWM
#ifdefでM_PIがないときだけ自分で定義するのが手っ取り早いと思うけど。
2018/09/01(土) 18:57:55.32ID:uNlfHVUP0
>>115
乙。てかreactOSって使い物になるのか?
無理してWindows使うよりは、素直にLinuxに逃げるのが順当だと思うが。
2018/09/04(火) 02:12:16.08ID:I66W1B5fd
>>119
使い物にするのが、依頼人の要望だから、私はそれを、果たすのみ。。。
2018/09/24(月) 03:37:05.87ID:1deJaFMg0
上級者ではないんだけど 経験豊富な人に訊きたいのでここに書きます
https://git.musl-libc.org/cgit/musl/tree/include/stdlib.h
↑ここなどを見るとEXIT_SUCCESSは0で固定されています(OSによる場合分けがない)。
ということは少なくもMusl LibCプロジェクトは正常返り値を0と決めてかかっているということでしょう。

WindowsやUnix系のOSでは正常返り値は0ですが、ほかの値は絶対に考えなくていいのでしょうか
みなさんはいままで正常返り値が0でない処理系(というかOS)を見たことなどありますか。
2018/09/24(月) 04:02:22.36ID:bIT2p0fxa
0が成功を示すと規格で決まっております。
2018/09/24(月) 12:40:59.88ID:indqm+5q0
>>121
もしプロセス終了コードの具体的な数値(数値かどうか)が異なるシステムがあるなら、
正常終了を示す main() の戻り値 0 をその環境用の終了コードで成功の値にマップするのは
そのシステム向けの処理系の仕事になる。

成功・失敗の区別以外に興味がない限りCのコードを書くプログラマが気にする必要はない
と規格は想定している。
124デフォルトの名無しさん (ワッチョイ c123-wH+P)
垢版 |
2018/09/24(月) 13:59:06.82ID:KzNCIBHJ0
>>121
おまいWindowsでexe実行したとき必ず戻り値みてるか?
BATとかあるけどさ
2018/09/24(月) 17:18:25.80ID:1deJaFMg0
>>123
なるほど crt0あたりでmainから0が来た場合の本当の成功判定を処理してるってことですね。
ありがとうございました。
126さまよえる蟻人間 ◆T6xkBnTXz7B0 (ワッチョイ 67b3-7Kxw)
垢版 |
2018/10/14(日) 11:56:24.75ID:7zcwA4Ik0
せっかく上級者が集まっているんだし、評論でもやりましょう。
https://github.com/reactos/reactos/blob/master/win32ss/gdi/ntgdi/freetype.c
このソース、俺の担当なんだけど、ひまだったら
喧嘩上等で悪い所・直すべきところを全部指摘してくれ。頼むよ。
127デフォルトの名無しさん (アウウィフ FFeb-NsMu)
垢版 |
2018/10/14(日) 12:52:43.56ID:G4e8iFcgF
やっぱwindowsは糞だな
2018/10/14(日) 13:31:35.13ID:p/Li638e0
>>126
書き換えた所はどこ?
2018/10/14(日) 13:57:45.50ID:m0LzoO8+0
頑張ろうと思ったんだが、暇つぶしでやるには長すぎて挫折した。すまん。
2018/10/14(日) 13:58:41.27ID:b97yHnkE0
>>126
IntCharSetFromCodePage の for の中のひとつ目の if は削除して、for に入るまでに
if( uCodePage == 0 ) return DEFAULT_CHARSET;
をやる。
for に入るまでの if は 確率が高い順に並べる。

とか?
2018/10/14(日) 15:07:42.66ID:p/Li638e0
>>126
表面的になぞっただけで、意味は読んでいないから参考程度で。

L924-931、FW_*のenumに揃えられるのなら揃えた方がいい。あと、ベタで書くよりはループが良いかも。
L946関数他、InterLockを外部的に明示的に行っているけど、俺ならアクセス関数内に押し込む。
ただこれは以前揉めたから、他の流儀の奴もいるのかもしれない。
俺の考えとしては、enumやdefineする理由は、変更箇所を1ヶ所に留める(同期させずに済む)事だと考えているので、
外部的に明示的にInterLockをその都度行うのは、変更時に全ての場所を同期させる(同様に書き換える)必要があるという意味で悪手。
敢えてInterLockしていることを誇示したい等の他の理由がなければ、アクセス関数内に押し込む。
L2024,L2040,L2052,L2135、同じ事を4回書いてる。
おそらく全体的に低レベルまで全部触りに行く、ある意味Cに典型的なコードになっている。
嫌う人もいるとは思うが、俺ならこの4回をどうにか1つに纏めて抽象度を上げていく。
4つの*NameWを常に同時に使うものなら、普通はstructにする。
L2879とL2888で、FT_Done_GlyphとDPRINT1の順序が逆。
お互い干渉しないから問題なしなのだろうけど、可能なら順番は揃えた方がいい。
しかもL2926とL2934でも順番が逆なので、L2869-とL2923-ってコピペしてるだろこれ。
そういうのはマメにサブルーチンとして切り出すべし。でないと抽象度が上がらない。
L3567-L3581、同じ事を4回やってる。サブルーチンに切り出して xx=sub()の形で書くべし。
あと、リテラル(初期化構文)使えるのならリテラルで書いた方がすっきりすると思うが。
L5081-5112、悪いとは言わないが、どうにかならんのか?
失敗系の速度が大して必要ないなら、ReleaseAllResources()で if (NameInfo1!=0) ExFreePoolWithTagの様にして纏めるとか。
なおL5153、"WithTag"が無いバージョンを呼んでいるが大丈夫なのか?
可能であればL5162で関数切って2つの関数にした方がいいと思う。(リソース確保/失敗系と成功系を分ける)
L5889とかもそうだけど、おそらく全部のメンバを初期化してるだろ。だったら初期化構文使った方が見た目分かりやすい。
2018/10/14(日) 15:08:04.46ID:p/Li638e0
ただし、上記は「ソースを綺麗にする方法」であって、通常は速度は落ちるので注意。
酷い話、ベタで書きまくっている方が速いのも事実。
あと、既に言ったが、上記はなぞっただけであり、関数内しか見てないので注意のこと。
本当に問題なのは関数間であり、それはガチで時間をかけて読まないと分からないから、そこまではやる気無い。
ただ、この雰囲気なら、2割くらいの関数は整理(削除)出来るのではないかと思うけど。

自分でも気になっているところがあるのなら、それを先に言うべし。見るから。
2018/10/14(日) 15:31:36.33ID:7zcwA4Ik0
気になってることと言えば、TextOutでOPAQUEモードのときに背景を塗り潰さないといけないのだが、それを一個の長方形でいっぺんに出来ないかな。
2018/10/14(日) 15:35:42.20ID:p/Li638e0
>>133
とりえあず行番号と関数名を言え。
それとも、そのソースではない一般の話?
(Ctrl-Fでは6ヶ所引っかかるが)
2018/10/14(日) 15:44:21.77ID:p/Li638e0
ちなみに、これって、実際にフォントをレンダリングしているんだよな?2次ベジエ等で。
なら、OPAQUEの場合は先に塗りつぶしておいた上に描いた方が楽だと思うけど。
再帰等の条件に描画情報を使っていてそれが出来ない場合、反転でAND取ってORすれば昔のPSETにはなる。
(フォントの黒部分にもAlpha値があるのなら全面的に計算するだけだから、これではなさそうだし)
2018/10/14(日) 15:45:29.84ID:7zcwA4Ik0
>>134
GreExtTextOutW関数のL5847...L5954です。
2018/10/14(日) 15:47:47.17ID:7zcwA4Ik0
>実際にフォントをレンダリングしているんだよな?2次ベジエ等で。
FreeTypeというフォントレンダリングライブラリでビットマップとアウトライン曲線を取得しています。

>OPAQUEの場合は先に塗りつぶしておいた上に描いた方が楽だと思うけど。
そうしてます。
2018/10/14(日) 15:51:46.90ID:7zcwA4Ik0
>>130
それはないかな。すみません。
139さまよえる蟻人間 ◆T6xkBnTXz7B0 (ワッチョイ 67b3-7Kxw)
垢版 |
2018/10/14(日) 16:02:11.24ID:7zcwA4Ik0
>>131
WithTagの指摘、助かった。ありがとう。
https://github.com/reactos/reactos/pull/941
他の件については後程、検討する。
2018/10/14(日) 16:16:37.97ID:7zcwA4Ik0
4つの*NameWの件、修正してみた。ありがとう。
https://github.com/reactos/reactos/pull/942
2018/10/14(日) 16:28:37.53ID:p/Li638e0
>>137
> それを一個の長方形でいっぺんに出来ないかな。
L5853のfor文が気になっているのなら、多分このCountは文字数で、
英文の場合は文字種類間ごとにピッチを変えるからこうなっているのでは?(いわゆるプロポーショナルフォント)
1回の操作に纏めたければ、文字単位でビットマップを生成して重ねるのではなく、
あらかじめ全体のビットマップを作ってそこにレンダリングしていけばいいのだけど、
速度的には速くなりそうだけど、後々面倒だから文字単位にしているのではないかと。

ここを文字単位でしこしこやるのは、悪いことではないと俺は思うけど。
気になっているのは被る部分が2度レンダリングされるって事かな?
幅5pxで1px被ってたら20%高速化だから地味に大きいのも事実だけど。
書き換えたいのなら後述参照。

なお、本筋とは異なるが、L5885-5887, L5926, L5938は正常系でもDPRINTしてるが大丈夫なのか?
DPRINT自体がリリースビルドでは消される仕様なら問題ないが。

>>139
正直なところ、指摘は参考に留めて、必要ない限りあまりいじらない方が良いとは思う。
これは昔の「動いているコードを触るな」であり、今風の「積極的にリファクタしろ」ではないが、
リファクタはデグレードをガッツリ検出出来る環境があればこそであって、
例えばchromeとかはそれをガチガチにやっているから出来るのであって、
検証環境のサポート無しなら、バグだと分かったところだけ修正し、そのついでに書き換える程度の方がいいと思うよ。

それで、該当部分を書き換えたいのなら、俺なら以下の手順でやる。(自己でデグレードチェックをする)
1. 対象部分、5847-5954を関数に切り出す。
2. その関数と全く同じ出力を生成する新関数(書き換えて1回でレンダリングするもの、おそらく20%程高速)を作る。
3. 両方とも呼び出す形でデバッグビルドし、結果を常に比較する状態でしばらく動かす。
 具体的には、旧関数出力と新関数出力のビットマップを全比較する。
 フォントのレンダリングなんてものすごい回数行われるので、バグっているようなら大抵これで検出出来る。
高速化は結構すると思うから、書き換える意味はあるとも思うけど。やるなら頑張れ。
2018/10/14(日) 19:15:26.67ID:p/Li638e0
>>139
はえーよ

>>140
第一段階としてはそれで良い。

(以下は改変後の行番号として)
ただ、オブジェクト指向的にはL2033-2036の中身をいちいち見せてNeededに足すのは悪手で、
可能なら AllLengthというプロパティを作りたいところ。
Cなら関数FONT_NAMES_get_all_length()とかで「中身を知らなくても全部の長さが分かる」様にして疎結合化する。
(後々fontNamesにメンバが追加されても struct FONT_NAMES の変更だけで済むようになる)

それで、L2125-L2141でご丁寧に全部Otm(の後ろ)にコピーしてるだろ。
これだと、多分、本来はOtm内に FONT_NAMES 構造体を持ち、そこに構造体のコピーで済むように書けるはず。
具体的には、

Otm->FontNames = FontNames; // --- (α)

みたいな。
2018/10/14(日) 19:15:52.58ID:p/Li638e0
ただこれ、データ埋め込みだから Otm->otmFamilyName等はオフセットで管理し、
不要なUNICODE_STRING構造体部分は破棄して文字列実体だけコピーするケチケチ作戦か?
なら、普通は文字列実体のコピー関数をメンバ関数として用意する。Cなら、

char* UNICODE_STRING_copy_string(UNICODE_STRING* ustr, char* Cp){ // --- (β)、一応thisを第1引数にした
wcscpy((WCHAR*) Cp, ustr.Buffer);
return Cp + ustr.Length + sizeof(WCHAR);
}

そしてL2124-2126を

Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
Cp = UNICODE_STRING_copy_string(FamilyNameW, Cp); // --- (γ)

として、実装をはがしていく。(疎結合化する)
これで UNICODE_STRING 内にメンバ Buffer と Length があることを知らなくてもコピー出来るようになった。
同様に、Otm内に直接FontNames(または文字列実体だけコピー済みのchar*)を持つようにして、
FontNamesと同じ型を使い回せるようにすれば、もっと記述は少なくて済むし、疎結合化していく。(α)

ただし、ここら辺がLinusが嫌う、C++が逆に結合していく部分であって、
コード上の静的コールグラフでは疎結合化するが、型を通して知識的に密結合してしまう、というところ。
具体的には、FontNamesで綺麗に書こうとすれば OUTLINETEXTMETRICW に FONT_NAMES を持たせるべきだが、
これをやると、OUTLINETEXTMETRICWを使う人は全員FONT_NAMES構造体を知っていけないといけなくなる。
今のところ FONT_NAMES 構造体はオレオレ構造体であり、これは避けるべきだ。
逆に、UNICODE_STRINGはおそらく全体で使われている構造体なので、
(β)の関数を用意したら他でも色々使い回せ、全体的に記述を減らせるはず。
だから、次の手としては(β)+(γ)で記述を減らすべきだ。
ただし、もし仮に、型 OUTLINETEXTMETRICW を使うときには常に FONT_NAMES 構造体を知っているべきだ、というのであれば、
(α)の方向に変更していった方が最終的には綺麗になる。

てゆーか、頭大文字でも変数なのかー、まあそういうルールならそれでいいが。
2018/10/14(日) 19:38:11.68ID:p/Li638e0
>>143訂正
× .
○ ->
見れば分かるとは思うが。
2018/10/14(日) 20:06:34.30ID:kaj6ZYWld
https://github.com/reactos/reactos/pull/945
若干の改良。
2018/10/14(日) 20:21:41.00ID:kaj6ZYWld
OUTLINETEXTMETRICS構造体はwin32apiで定義済みだから、我々はそれを変更できない。
2018/10/14(日) 20:35:16.55ID:p/Li638e0
>>145
ご苦労様。

俺は書き換え後の方が断然いいと思うが、
3回+αだったから意外に効果が少なく、評価は分かれるかもね。
なにげに「書けばいいだろ」方式のべた書きって記述量は意外に少なかったりするし、今回もそうだった。


>>146
なるほど。
なら俺なら(β)+(γ)で主関数(IntGetOutlineTextMetrics)を4行減らす。
ただし、実際はサブ関数(γ)で4行増えるので、全体の記述量は変わらず、これも評価が分かれるかも。
UNICODE_STRING構造体も、変更があり得ないほどなら、ベタに密結合させて書いても問題ないからね。
2018/10/14(日) 21:51:10.52ID:p/Li638e0
>>140
すまん、見落としてた。
その場合、普通は4つのIntGetFontLocalizedNameもIntInitFontNamesに突っ込む。

というかな、一応オブジェクト指向を意識して書いた方が分かりやすいと思う。
FONT_NAMES構造体に纏める=そのメンバはほぼ常にセットで使う、という意味なのだから、
初期化も常にセットで行うべきなんだよ。それがコンストラクタであって。
だから、構造体に纏めた時点で、出来る限り「構造体」でアクセスすべきであって、
構造体の「メンバ」をいちいち無駄に参照するべきではない。
その場合、

IntInitFontNames(&FontNames, SharedFace, gusLanguageID);

としてしまって、メンバ全部を一度に初期化してしまうべき。

void FASTCALL IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace, ... ) // てか gusLanguageIDってどこからくるんだオイ?
{
RtlInitUnicodeString(&Names->FamilyNameW, NULL);
IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
// その他*3
}

てな感じ。
2018/10/14(日) 22:44:56.36ID:p/Li638e0
で、さらについでに言うと、最後のコピーもメンバ関数として切り出して終わりだ。
つまり、FONT_NAMES構造体は、

void FASTCALL IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace, unkownType gusLanguageID); // コンストラクタ
void FASTCALL IntFreeFontNames(FONT_NAMES *Names); // デストラクタ
void FASTCALL SetFontNameAddresses(FONT_NAMES *Names, LPSTR **FamilyName, LPSTR **FaceName, LPSTR **StyleName, LPSTR ** FunnName); // コピー部分

の3つをメンバ関数として持ち、外部からは4つのメンバ変数

FamilyNameW, FaceNameW, StyleNameW, FullNameW;

をアクセスする必要が無くなるからprivateにしてしまえ、というのがオブジェクト指向になる。
結果、上位関数IntGetOutlineTextMetricsは、

IntInitFontNames(&FontNames, SharedFace, gusLanguageID);
で初期化して、駄目なら
IntFreeFontNames(FontNames);
を呼び、成功なら
SetFontNameAddresses(&FontNames, &Otm->FamilyName, &Otm->FaceName, &Otm->StyleName, &Otm->FunnName);
を呼んで終わる、と単純化される。


ところで、この書き方だと RtlInitUnicodeString と IntGetFontLocalizedName でも
alloc失敗で0が返ってきて落ちる様な気がするのだが、
これに対して対策されてないのは大丈夫なのか?
2018/10/14(日) 23:00:29.98ID:p/Li638e0
>>149
自己レス。
RtlInitUnicodeString と IntGetFontLocalizedName については大丈夫っぽい。


IntGetFontLocalizedNameは元のL2408で

Status = STATUS_INSUFFICIENT_RESOURCES;

を食らう可能性があって、この場合は FONT_NAMES.FamilyNameW等は正しく初期化されない可能性がある。
プログラムフロー的にこれがないと言えればいいが、そうでない場合は

Needed += FontNames.FamilyNameW.Length + sizeof(WCHAR);

でいきなりLengthを見に行くのはそれなりに危険。

ただ、見たところ常に RtlFreeUnicodeString を先に呼んでて、
(これは無いから正確ではないが、)
名前やフローからするとおそらく Length = 0 してくれてるから多分大丈夫だね。
誰か探してくれば見ますが。
2018/10/16(火) 19:22:32.13ID:Fb63Sgww0
https://github.com/reactos/reactos/pull/942/files/13fe63ede025c7a802676b4d95fc9287c95fa8be
見たぜ。割といいね。

俺なら RtlInitUnicodeString と IntGetFontLocalizedName は元のように交互にする。
それの方がこれらは「セット」だと分かりやすいから。

あと、gusLanguageID がグローバルを掴むのはちょっといやなので、コンストラクタで与える。
必要なら(今回は要らないはずだが)内部で保持して、それを使い回す。
2018/10/16(火) 19:22:49.09ID:Fb63Sgww0
一般的にいうと、今は FONT_NAMES 構造体がグローバル変数 gusLanguageID に依存してしまっている。
つまり、 gusLanguageID を変更すると即座に動作が変わってしまう。
今回はコンストラクタ IntInitFontNames 内でしか使ってないから問題ないはずだが、
後々 gusLanguageID を使うようなメンバ関数が追加されたりしたら挙動がおかしくなる。
それは外面的に見えるものでもない。
例えば、(今回は違うが) RtlInitUnicodeString のような、
引数に gusLanguageID を用いないが、内部的に使っている関数や構造体があったとして、
それをメンバ関数で使うと、「初期化時の gusLanguageID と違う ID を途中から使う」事になり、挙動がちぐはぐになる。
しかし、これはコード上では見つけにくい。
だから、これを防ぐ為に、普通はグローバル変数に直接依存することは避け、コンストラクタで与え、
必要なら内部で保持して、それを使い回す。
これにより、初期化時と同じIDで動作するようになり、ちぐはぐな動作は避けられる。

同様に、今は FONT_NAMES 構造体が グローバル変数 gusLanguageID に依存していることは外面的(引数的)には見えない。
だから、FONT_NAMES 構造体を使い回すと、使う側が gusLanguageID への依存を意識出来ず、バグの温床になる。
そうではなく、コンストラクタ引数で gusLanguageID も与え、
IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace, unknownType gusLanguageID)
とすれば、gusLanguageID への依存は明示的だから、この辺が避けられる。そして
IntGetFontLocalizedName( ... , gusLanguageID);
が gusLanguageID を引数にいちいち積んでいるのもそのため。
直接依存は避け、明示的に gusLanguageID を与えることにより、バグの温床を潰してる。
(動けばいいだけなら、グローバル変数を引数に積むのは無駄でしかないし)
2018/10/16(火) 19:23:14.27ID:Fb63Sgww0
コード全体のポリシーとして、 gusLanguageID にそれぞれが直接依存し、
その変更一つで瞬時に全体の動作を切換え、引数の数を減らして高速化し、引数の伝言ゲームを減らしてコードもすっきり、
というのはありだし、実際にCのコードでは結構見かける。
ただ今回の IntGetFontLocalizedName はそうなっていない。
こちらは普通のポリシー「グローバル変数には闇雲に依存しない」という方針で書かれている。
(だから引数でグローバル変数を積んでいる)
今回の FONT_NAMES 構造体は後発だし、当然既存のルールに合わせるべきだから、
IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace, unknownType gusLanguageID)
として、グローバル変数への依存を切る、という既存のルールに合わせるべきだ。

(逆に、敢えて高速化等の為に依存する、というのなら、
IntGetFontLocalizedNameUsingGlobal(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY)
として、 IntGetFontLocalizedName もグローバルに直接依存するべき。そうしないと効果がないから。
外面的(コンストラクタ引数)では依存せず、内部的には IntGetFontLocalizedName 関数で依存している、というのは、
単にバグの温床でしかないから、どちらかに揃えるべき。普通はグローバルへの依存は切る。)

そもそもオブジェクト指向的に「実装を切り離す」のは、実装の中身(コード)を読まなくてもよくする為。
だから、見た目依存してなさそうなところに依存する構造にするのは間違いだし、バグの元。
コンストラクタで与える変数のみに依存する、というのが一番分かりやすいでしょ。
だから普通はそうする。

君もだが、一般的にCのコードはこの辺が甘い。
これはCでは「実装」を記述する為で、
つまり「グローバルなんて積んでも積まなくても動くんだから、どっちでもいいでしょ」な訳だ。
対してオブジェクト指向のコードは、「設計」を記述する為、引数に何を積むべきで、何を積んではいけないか、
或いはその関数が本来どこに存在すべきなのか、この辺に厳しい。
この辺は勉強になるから、Cでもオブジェクト指向は知っておいた方がいい。
ただ、Javaとかのはかなり暴走しているから、「本来の」オブジェクト指向の範囲に留めた方がいいのも事実だが。
2018/10/16(火) 19:23:33.27ID:Fb63Sgww0
纏めると、コードはつまり、

A:
IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace, unknownType gusLanguageID) {
IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
}

B:
IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace) {
IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
}

C:
IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace) {
IntGetFontLocalizedNameUsingGlobal(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY);
}

の3種類のどれかになる。普通はグローバル変数 gusLanguageID への依存を明示的に切るAにする。
対してCは「意図的にグローバル変数に依存する」コードであり、これも場合によってはありだ。
君のコードはBで、これは最終的にCを目指す過渡的なコードとしてはありだが、
そのつもりがない場合、ここでBを持ってくるのは間違いで、Aにするべきだ。

OtmSize を FONT_NAMES 構造体のメンバに持ったのはいい。これが綺麗だろう。
IntStoreName が長さを返すというのもいい。
(正直、俺も長さを返す方がいいかとも思ったが、その場合、ナマポに直接足し算が必要になるのでこれを避けた。
ただ、Cだし、コピーの場合は長さを返す方が常識的だし、これの方がいいだろう。)
マクロでやるべきかはともかく、 (+32)>>6 もうざかったから掃除したのはいい。
が、それも本来は、 copy_scales(Otm, pOS2, Face); とかにしておさらばしたいところだね。
それ、同じような名前のをグダグダコピーしないといけないのは、本来は継承関係があれば防げた話だ。
Otmはwin32APIだから変更不可として、pOS2の方も駄目なの?
(仮に出来たとしても大手術になるだろうから先送りでいいが)
2018/10/16(火) 22:05:32.39ID:gb9oBO7dd
頭にFT_が付くのはfreetypeの識別子だ。freetypeライブラリそのものは、設定項目以外は編集できない。
2018/10/16(火) 22:26:02.42ID:Fb63Sgww0
>>155
ああなるほどね。

それなら freetype -> win32API の変換関数群をひとまとめにしておきたいところだが、
それが freetype.c そのもの、というわけか。
なら、freetype.c 内で1回グダグダコピーするのは致し方ないし、そのコードで妥当だ。

ただまあ、正直なところ、コードのリファクタは将来への投資であって、
実利自体はないし、やり出すとキリがない。
気になってるところがあるのだから、さっさとそこに取りかかった方がいいと思うぜ。
フォントエンジンが速くなれば、地味にOSのレスポンスも上がるはずだし、喜ばれると思うよ。
2018/10/29(月) 22:10:10.28ID:PActy/D6d
https://gist.github.com/katahiromz/36f7135d3afe9fe6d2b7b28816be0f30

Can you read this ReactOS codes?
2018/10/30(火) 21:47:14.89ID:jbTXNLFK0
>>157
読める/読めないなら、読めるだろう。
リソース確保して実行して解放する、上位コードに見える。
ただし、何をやっているかは正確には分からない。(部外者だからだが)
パスを取って、広げて、レクタングルのリージョンにして、クリップして、ペイントしているから、画像系の何かだろう。

ただ、前から思っているのだが、(君のせいではないが)
リソース確保、普通にネストにした方が良くないか?

retval = false;
a = malloc(...);
if (a) {
b = malloc(...);
if (b) {
c = malloc(...);
if (c) {
retval = true;
free(c);
}
free(b);
}
free(a);
}
return retval;

それ、ネストを嫌うあまり、PATH_Delete(pPath->BaseObject.hHmgr); を3回もコピペしてるだろ。
それじゃ逆に意味無い。バグの検出が難しくなり、コードの品質が下がる。
(同じ努力でデバッグした場合、比較的コード品質が低いままになる)
2018/10/30(火) 21:47:51.74ID:jbTXNLFK0
上記のコード、freeは1回ずつしかないから、忘れてたら『常に』リークする。
だから、バグの検出が容易となる。(すぐ検出出来る)
GitHubのコード、3つ目のPATH_DELETEは正常系だからここを忘れたらすぐに検出出来るけど、
1つ目のところで忘れたら、容易には検出出来なくなる。
結果的に、バグっててもなかなかヒットせず、バグを残してしまう。
「バグを検出しやすい構造」ってのも、コード品質を上げる為には重要だよ。
前も思ったけど。前は4回コピペしてたでしょ、確か。

正しく全部書ききればいい、それは事実だけど、実際それが難しいからバグになるのであって。

この意味ではGo言語も糞だ。
JSONの定義をしたら、定義、仕様、タグ、と3回「同じ事を文法的に書かなければならない。」
俺は早々にそれに遭遇して、もうGoは使わないと心に誓った。
俺は上記のように、コードを重複させないことに重きを置くから。
このコードのように、何度べたべた書いても平気な人は、Goも許せるのだろうけど。
ただこんな書き方だと、細かいバグが永久に取りきれないと思うけどね。

オブジェクト指向の、メソッドを集中使用するやり方は、実は地味に効いてる。
あれだと、メソッドのバグは速攻検出されるので、コード品質は上がりやすい。
2018/10/31(水) 18:43:08.64ID:Gx8awWOCM
リソース確保はループかプールで必ず成功するようにできんか?
2018/10/31(水) 18:56:15.53ID:f1tmQgGe0
ループでは無理だろ
ここでプールを使うのも最悪だ
2018/11/01(木) 20:00:57.97ID:1k1Ne2fSa
クリティカルコンテキストでもないのにプールは無駄。
ループでリソース確保するのはプロジェクトのポリシー次第。
163さまよえる蟻人間 ◆T6xkBnTXz7B0 (ワッチョイ 8bb3-PRUr)
垢版 |
2018/11/02(金) 12:02:06.04ID:pL4zzXZg0
ReactOSのバグ案件がまた来た。
以前に「Fix font metrics」というコミットをしたわけだが、、、
https://github.com/reactos/reactos/commit/35f62fc5ba0b69e7335ff41400cb3b45660f4557
これがどうやらguilty commitらしい。
一つ目の案件。https://jira.reactos.org/browse/CORE-15303
二つ目の案件。https://jira.reactos.org/browse/CORE-15166
ちなみにrappsというのは、ReactOS Applications Managerのことだ。
現在の実装は以下の通り。
freetype.c: https://github.com/reactos/reactos/blob/master/win32ss/gdi/ntgdi/freetype.c
text.c: https://github.com/reactos/reactos/blob/master/win32ss/gdi/ntgdi/text.c
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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