我正在嘗試讀取datafileC 中的二進制檔案。這個二進制檔案顯然包含 32 位(4 位元組)整數。我被告知二進制檔案是使用以下代碼片段生成的:
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
.....
int fd = open("datafile", O_CREAT|O_WRONLY, 0600);
if(fd >= 0) { // IFF FILE OPENED SUCCESSFULLY
for(int32_t i = -50 ; i<50 ; i ) {
write(fd, &i, sizeof(i));
}
close(fd);
}
我得到了以下用于讀取二進制檔案的代碼:
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
int main(void) {
int fd = open("datafile", O_RDONLY, 0);
if(fd >= 0) {
for(int32_t i = -50; i < 50; i ) {
int32_t value;
read(fd, &value, sizeof(value));
printf("%4i\t0xx\ti\t0xx\n", i, i, value, value);
}
close(fd);
}
return 0;
}
有人告訴我,這段代碼應該將二進制檔案的值列印為十進制和十六進制值。我的輸出如下:
-50 0xffffffce 255 0x000000ff
-49 0xffffffcf 255 0x000000ff
-48 0xffffffd0 255 0x000000ff
-47 0xffffffd1 255 0x000000ff
-46 0xffffffd2 255 0x000000ff
-45 0xffffffd3 255 0x000000ff
-44 0xffffffd4 255 0x000000ff
-43 0xffffffd5 255 0x000000ff
-42 0xffffffd6 255 0x000000ff
-41 0xffffffd7 255 0x000000ff
-40 0xffffffd8 255 0x000000ff
-39 0xffffffd9 255 0x000000ff
-38 0xffffffda 255 0x000000ff
-37 0xffffffdb 255 0x000000ff
-36 0xffffffdc 255 0x000000ff
-35 0xffffffdd 255 0x000000ff
-34 0xffffffde 255 0x000000ff
-33 0xffffffdf 255 0x000000ff
-32 0xffffffe0 255 0x000000ff
-31 0xffffffe1 255 0x000000ff
-30 0xffffffe2 255 0x000000ff
-29 0xffffffe3 255 0x000000ff
-28 0xffffffe4 255 0x000000ff
-27 0xffffffe5 255 0x000000ff
-26 0xffffffe6 255 0x000000ff
-25 0xffffffe7 255 0x000000ff
-24 0xffffffe8 255 0x000000ff
-23 0xffffffe9 255 0x000000ff
-22 0xffffffea 255 0x000000ff
-21 0xffffffeb 255 0x000000ff
-20 0xffffffec 255 0x000000ff
-19 0xffffffed 255 0x000000ff
-18 0xffffffee 255 0x000000ff
-17 0xffffffef 255 0x000000ff
-16 0xfffffff0 255 0x000000ff
-15 0xfffffff1 255 0x000000ff
-14 0xfffffff2 255 0x000000ff
-13 0xfffffff3 255 0x000000ff
-12 0xfffffff4 255 0x000000ff
-11 0xfffffff5 255 0x000000ff
-10 0xfffffff6 255 0x000000ff
-9 0xfffffff7 255 0x000000ff
-8 0xfffffff8 255 0x000000ff
-7 0xfffffff9 255 0x000000ff
-6 0xfffffffa 255 0x000000ff
-5 0xfffffffb 255 0x000000ff
-4 0xfffffffc 255 0x000000ff
-3 0xfffffffd 255 0x000000ff
-2 0xfffffffe 255 0x000000ff
-1 0xffffffff 255 0x000000ff
0 0x00000000 255 0x000000ff
1 0x00000001 255 0x000000ff
2 0x00000002 255 0x000000ff
3 0x00000003 255 0x000000ff
4 0x00000004 255 0x000000ff
5 0x00000005 255 0x000000ff
6 0x00000006 255 0x000000ff
7 0x00000007 255 0x000000ff
8 0x00000008 255 0x000000ff
9 0x00000009 255 0x000000ff
10 0x0000000a 255 0x000000ff
11 0x0000000b 255 0x000000ff
12 0x0000000c 255 0x000000ff
13 0x0000000d 255 0x000000ff
14 0x0000000e 255 0x000000ff
15 0x0000000f 255 0x000000ff
16 0x00000010 255 0x000000ff
17 0x00000011 255 0x000000ff
18 0x00000012 255 0x000000ff
19 0x00000013 255 0x000000ff
20 0x00000014 255 0x000000ff
21 0x00000015 255 0x000000ff
22 0x00000016 255 0x000000ff
23 0x00000017 255 0x000000ff
24 0x00000018 255 0x000000ff
25 0x00000019 255 0x000000ff
26 0x0000001a 255 0x000000ff
27 0x0000001b 255 0x000000ff
28 0x0000001c 255 0x000000ff
29 0x0000001d 255 0x000000ff
30 0x0000001e 255 0x000000ff
31 0x0000001f 255 0x000000ff
32 0x00000020 255 0x000000ff
33 0x00000021 255 0x000000ff
34 0x00000022 255 0x000000ff
35 0x00000023 255 0x000000ff
36 0x00000024 255 0x000000ff
37 0x00000025 255 0x000000ff
38 0x00000026 255 0x000000ff
39 0x00000027 255 0x000000ff
40 0x00000028 255 0x000000ff
41 0x00000029 255 0x000000ff
42 0x0000002a 255 0x000000ff
43 0x0000002b 255 0x000000ff
44 0x0000002c 255 0x000000ff
45 0x0000002d 255 0x000000ff
46 0x0000002e 255 0x000000ff
47 0x0000002f 255 0x000000ff
48 0x00000030 255 0x000000ff
49 0x00000031 255 0x000000ff
但輸出實際上應該如下:
-50 0xffffffce -822083585 0xceffffff
-49 0xffffffcf -805306369 0xcfffffff
-48 0xffffffd0 -788529153 0xd0ffffff
.....
-3 0xfffffffd -33554433 0xfdffffff
-2 0xfffffffe -16777217 0xfeffffff
-1 0xffffffff -1 0xffffffff
0 0x00000000 0 0x00000000
1 0x00000001 16777216 0x01000000
2 0x00000002 33554432 0x02000000
3 0x00000003 50331648 0x03000000
.....
47 0x0000002f 788529152 0x2f000000
48 0x00000030 805306368 0x30000000
49 0x00000031 822083584 0x31000000
如您所見,盡管我的前兩列似乎與預期的一樣,但最后兩列與應有的完全不同。我的最后兩列只是重復列印出相同的兩個值255和。0x000000ff這是怎么回事,我該如何解決?
uj5u.com熱心網友回復:
將評論轉換為答案。
JL:如果檔案是在讀取檔案的同一臺機器上寫入的,我看不出如何從輸入資料中獲得“預期輸出”。似乎期望該檔案是在小端機器上生成并在大端機器上讀取的,反之亦然。
TP:我從來沒有聽說過這個“endian”的概念。我正在使用 macOS,如果有幫助的話。
JL:你知道是誰創建了資料檔案嗎?是您在您的 Mac 上,還是其他人(講師)創建的?你知道他們在什么機器上創建它嗎?您可以在Endianness的 Wikipedia(還有哪里?)上找到有關“endian-ness”的資訊。您的 Mac 可能使用 Intel 芯片,因此使用 little-endian 順序。AFAIK,即使是 M1 Mac 也使用 little-endian。但是 SPARC 和 PowerPC 使用大端順序(盡管 PowerPC 現在是可切換的,并且有一個 PPC-LE 版本的 Linux)。
TP:看起來二進制檔案可能是在“Sun SPARC 計算機”上創建的(代碼可能已經執行過)。但它暗示讀取這個二進制檔案應該在 Intel 64 位 x86 處理器上作業(顯然,我們不期望我們應該使用 Sun SPARC 計算機)。
JL:正如我在之前的評論中添加的,SPARC 是一個大端機器。因此,您現在需要找出操作
value未設定的原因read。檢查 from 的回傳值read()可能會提供資訊——如果不是 4,則有問題。是的,您可以毫無問題地讀取 Mac 上的資料,然后您應該會得到類似預期的輸出。
TP:我只是一個初學者的系統程式員,所以這遠遠超出了我所知道的范圍。根據 POSIX
read(),read()回傳一個int,所以我在一個變數中捕獲了該值并將其列印出來。它列印出 0,根據檔案,這似乎與預期的一樣。為什么我們期望它是 4?
該read()函式被告知最多讀取 N 個位元組并回傳它實際讀取的位元組數。零位元組讀取意味著“沒有更多資料”,俗稱 EOF 或“檔案結尾”。當你要求它讀取 4 個位元組時,它應該回傳 4,除非檔案中沒有那么多資料。
JL:對資料檔案進行十六進制轉儲:
xxd datafile | sed 1q應該產生00000000: ffff ffce ffff ffcf ffff ffd0 ffff ffd1(加上一系列 16 個點)。如果不是,則您的資料已損壞。我在我的 Mac 上撰寫了一個程式,以大端格式寫入資料(我使用在磁盤上使用大端格式的 DBMS,所以我有工具),然后你的閱讀代碼會產生預期的輸出。所以,我很困惑為什么你會得到 255/0x000000ff 輸出。您是否重新檢查過您沒有從閱讀代碼中洗掉任何字符。并檢查來自的回傳值read()。JL:為了清楚一點:使用大端資料檔案和問題中的讀取代碼,我在我的 Mac 上得到了預期的輸出(這個運行的是 Big Sur 11.6.5)。
TP: As I said, read returned 0, so I think that's as expected. Using
xxd datafile | sed 1q, I got00000000: ff .. So a small number of characters, then a lot of whitespace, and then a.. It seems very odd to me.
JL: Your data file is corrupted. It should have 400 bytes (
ls -l datafile). Andread()should only return 0 when it reaches the end of the file; every other time, it should return 4 (sizeof(int32_t)orsizeof(value)). You get 255 because there is a single byte with value 0xFF aka 255 (and the computing gods smiled on you — or maybe cursed you — and set the other bytes of value to 0).
TP: You're right! The file size was 400 bytes when I downloaded it, but it is now 1 byte! I have no idea how that happened. I have now re-downloaded it, and it seems to be working as expected! […]
Two lessons
- Check return values — especially from I/O functions.
- Check your data files (
ls -l,xxd, etc) to make sure they contain what you expect.
wr71le.c
This writes in 'native order' which is little-endian on an Intel machine.
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
int main(void)
{
int fd = open("datafile", O_CREAT | O_WRONLY, 0600);
if (fd >= 0)
{
for (int32_t i = -50; i < 50; i )
{
write(fd, &i, sizeof(i));
}
close(fd);
}
return 0;
}
wr71be.c
This writes in big-endian order on any type of machine — big-endian or little-endian.
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
typedef int32_t Sint4; // The st_sint4() code uses this type name
/*
** Convert signed 4-byte signed integer into 4-byte character array.
*/
static void st_sint4(Sint4 l, char *s)
{
s = sizeof(Sint4) - 1;
*s-- = l & 0xFF;
l >>= 8;
*s-- = l & 0xFF;
l >>= 8;
*s-- = l & 0xFF;
l >>= 8;
*s = l & 0xFF;
}
int main(void)
{
int fd = open("datafile", O_CREAT | O_WRONLY, 0600);
if (fd >= 0)
{
for (int32_t i = -50; i < 50; i )
{
char data[4];
st_sint4(i, data);
write(fd, data, sizeof(data));
}
close(fd);
}
return 0;
}
Output from xxd datafile
00000000: ffff ffce ffff ffcf ffff ffd0 ffff ffd1 ................
00000010: ffff ffd2 ffff ffd3 ffff ffd4 ffff ffd5 ................
00000020: ffff ffd6 ffff ffd7 ffff ffd8 ffff ffd9 ................
00000030: ffff ffda ffff ffdb ffff ffdc ffff ffdd ................
00000040: ffff ffde ffff ffdf ffff ffe0 ffff ffe1 ................
00000050: ffff ffe2 ffff ffe3 ffff ffe4 ffff ffe5 ................
00000060: ffff ffe6 ffff ffe7 ffff ffe8 ffff ffe9 ................
00000070: ffff ffea ffff ffeb ffff ffec ffff ffed ................
00000080: ffff ffee ffff ffef ffff fff0 ffff fff1 ................
00000090: ffff fff2 ffff fff3 ffff fff4 ffff fff5 ................
000000a0: ffff fff6 ffff fff7 ffff fff8 ffff fff9 ................
000000b0: ffff fffa ffff fffb ffff fffc ffff fffd ................
000000c0: ffff fffe ffff ffff 0000 0000 0000 0001 ................
000000d0: 0000 0002 0000 0003 0000 0004 0000 0005 ................
000000e0: 0000 0006 0000 0007 0000 0008 0000 0009 ................
000000f0: 0000 000a 0000 000b 0000 000c 0000 000d ................
00000100: 0000 000e 0000 000f 0000 0010 0000 0011 ................
00000110: 0000 0012 0000 0013 0000 0014 0000 0015 ................
00000120: 0000 0016 0000 0017 0000 0018 0000 0019 ................
00000130: 0000 001a 0000 001b 0000 001c 0000 001d ................
00000140: 0000 001e 0000 001f 0000 0020 0000 0021 ........... ...!
00000150: 0000 0022 0000 0023 0000 0024 0000 0025 ..."...#...$...%
00000160: 0000 0026 0000 0027 0000 0028 0000 0029 ...&...'...(...)
00000170: 0000 002a 0000 002b 0000 002c 0000 002d ...*... ...,...-
00000180: 0000 002e 0000 002f 0000 0030 0000 0031 ......./...0...1
rd71.c
This reads in native byte order.
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd = open("datafile", O_RDONLY, 0);
if (fd >= 0)
{
for (int32_t i = -50; i < 50; i )
{
int32_t value;
if (read(fd, &value, sizeof(value)) != sizeof(value))
{
fprintf(stderr, "Faulty read!\n");
exit(EXIT_FAILURE);
}
printf("%4i\t0xx\ti\t0xx\n", i, i, value, value);
}
close(fd);
}
return 0;
}
Output from rd71
-50 0xffffffce -822083585 0xceffffff
-49 0xffffffcf -805306369 0xcfffffff
-48 0xffffffd0 -788529153 0xd0ffffff
-47 0xffffffd1 -771751937 0xd1ffffff
-46 0xffffffd2 -754974721 0xd2ffffff
-45 0xffffffd3 -738197505 0xd3ffffff
-44 0xffffffd4 -721420289 0xd4ffffff
-43 0xffffffd5 -704643073 0xd5ffffff
-42 0xffffffd6 -687865857 0xd6ffffff
…snip…
40 0x00000028 671088640 0x28000000
41 0x00000029 687865856 0x29000000
42 0x0000002a 704643072 0x2a000000
43 0x0000002b 721420288 0x2b000000
44 0x0000002c 738197504 0x2c000000
45 0x0000002d 754974720 0x2d000000
46 0x0000002e 771751936 0x2e000000
47 0x0000002f 788529152 0x2f000000
48 0x00000030 805306368 0x30000000
49 0x00000031 822083584 0x31000000
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/456457.html
上一篇:新手:將指標傳遞給函式
