システム管理
キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 

64bitOSにおけるif文でchar*とuint32_t

TLSG01
貴重なコントリビューター

64bitOSにおけるif文でchar*とuint32_t

c8000 hp-ux11.i における

C言語のプログラム。

caddr_t 型 (実体はchar *らしい)

uint32_t 型 (実体はint らしい)

をif文で!=比較すると

printf文%xで見ると同じ値なのに

不一致判定(then)に進みます。

uint32_t ctl_addr;

struct isc_table_type *isc;

if ( isc->if_reg_ptr!=ctl_addr )

isc->if_reg_ptrとctl_addrが同じあるから elseに進ませたいのですが

コーディングをどのように訂正するべきでしょうか?

5 件の返信
nadachi
レギュラーアドバイザー

64bitOSにおけるif文でchar*とuint32_t

64bit OSで64bit対応のコーディングをしているわけですね。そうすると、

caddr_t はポインタ型ですから、64bit。

uint32_t はint型ですから、 32bit。

になります。それがif 文で != で比較して一致しないが、printf の "%x" フォーマットで表示すると同じパターンを示すとすれば、64bitデータのほうが

、32bitで収まらない大きさの数なのではありませんか?

 例えば、

$ more bbb.c

#include

main()

{

char *ptr;

unsigned int val;

val = 0x12345678;

ptr = (char *)(0x112345678);

printf("%x and %x\n", val, ptr);

if (val != ptr) printf("not equal\n");

else printf("equal\n");

printf("%lx and %lx\n", val, ptr);

}

をそれぞれ32bit、64bitアプリケーションとしてコンパイル、実行してみます。

--- 32bit アプリケーションとして、

$ cc bbb.c

cc: "bbb.c", line 8: warning 602: Integer constant exceeds its storage.

cc: "bbb.c", line 10: warning 609: Illegal integer-pointer combination for !=.

/usr/ccs/bin/ld: (Warning) At least one PA 2.0 object file (bbb.o) was detected.

The linked output may not run on a PA 1.x system.

$ ./a.out

12345678 and 12345678

equal

12345678 and 12345678

 32bitアプリケーションでは、unsigned int と

pointer のメモリ上での大きさは32bitで同じです。

-- 64bit アプリケーションとして、

$ cc +DD64 bbb.c

cc: "bbb.c", line 10: warning 733: != between 32 bit int and pointer.

$ ./a.out

12345678 and 12345678

not equal

12345678 and 112345678

 32bitでは収まらない数値をポインタ型変数に入れていますので、equal にはならない。printf の

"%x" フォーマットでは同じパターンを表示していますが、"%lx" フォーマットを指定すると、ポインタ側は32bit超のデータを表示しています。

 データ長の違う ctl_addr と isc とで、下位の32bitのみを比較したいのであれば、

if ( (uint32_t)(isc->if_reg_ptr & 0xffffffff)

!= ctl_addr) ) {

とでもすればよいとは思いますが、下位32bitのみの比較で、大丈夫ですか?

hazelwood
信頼あるコントリビューター

64bitOSにおけるif文でchar*とuint32_t

原因についてはnadachiさんの回答の通りですが、コーディングについては、uint32_tをvoid *などのポインタに変更すべきと思います。

(確か、HP-UXでの64bitプロセスのデータ領域のアドレスは、32bitで表現できる範囲を超えていたと思いますので。)

TLSG01
貴重なコントリビューター

64bitOSにおけるif文でchar*とuint32_t

printfにて%lXで値を見たところ

isc->if_reg_ptrは0xFFFFFFFFB02A0000

ctl_addrは0xB02A0000

と表示されました。

US HPに下記の情報が有ったので

型変換でやってみましたが

0xB02A0000はやはり0xB02A0000であり

if文は!=不一致へ進みました。

uint32_t barvalue; /* Value read from a PCI BAR */

caddr_t baraddr; /* PCI BAR's view of I/O address */

baraddr = (caddr_t)(uintptr_t)(barvalue & ~0xF);

試しに無理矢理 baraddrにisc->if_reg_ptrの値を

代入したらOSがクラシュ!!なぜだ??
nadachi
レギュラーアドバイザー

64bitOSにおけるif文でchar*とuint32_t

> isc->if_reg_ptrは0xFFFFFFFFB02A0000

> ctl_addrは0xB02A0000

> ...

> uint32_t barvalue; /* Value read from a PCI BAR */

> caddr_t baraddr; /* PCI BAR's view of I/O address */

ああ、baraddr はPCIバスの Base Address Registerのことですね。すると、"ctl_addr"は、PCIバスに載ったI/Fカード上のコントロールレジスタ側のPCIバス上でのアドレスですね。これはPCIバスだから32bitと。

 一方で、isc->if_reg_ptrのほうは、PA-RISCの64bitアドレスのようです。

 PCIバス側のアドレス空間を、PA-RISCの64bitアドレス空間の一部に対応(mapping)づける仕組みがあるのではありませんか? おそらくそれをしていないために、

> 試しに無理矢理 baraddrにisc->if_reg_ptrの値を

> 代入したらOSがクラシュ!!なぜだ??

ということだと思いますが。

TLSG01
貴重なコントリビューター

64bitOSにおけるif文でchar*とuint32_t

isc->if_reg_ptrはcaddr_t型なので

caddr_t ctladdr64 変数を用意。

uint32_t barvalue;

ctladdr64=(caddr_t)barvalue | 0xFFFFFFFF00000000;

で無理やり64bit pointer型を作り

比較することにしました。

一応、それなりに期待する動作をしていますが

このやり方は、本筋では無いはず。

なぜなら、これではせっかく64bitなのに

絶対に下位32bitしか使えない。