มีหลายวิธีในการพิมพ์การแทนค่าไบนารีสำหรับตัวเลขใดๆ ขั้นแรก คุณสามารถส่งออกผลลัพธ์ของการดำเนินการกะและดัชนีได้โดยตรง (ไปยัง stdout
ไฟล์ ฯลฯ...) นี่ดูเหมือนจะเป็นแนวทางที่คุณเริ่มใช้ แต่จากนั้นคุณก็ประกาศบัฟเฟอร์ 32 บิต แม้ว่าคุณจะสามารถทำได้อย่างแน่นอน แต่ก็ไม่จำเป็นต้องบัฟเฟอร์ผลลัพธ์หากคุณไม่ต้องการส่งคืนพอยน์เตอร์ไปยังบัฟเฟอร์ที่เสร็จสมบูรณ์ (นั่นนำฉันไปสู่จุดที่ 3 ของฉันด้านล่าง)
เพียงแค่ส่งออกบิตโดยไม่ต้องจัดเก็บ/ส่งคืนตัวชี้ไปยังบิตในสตริง สิ้นสุดด้วยค่า nul จะมีตำแหน่งอยู่ แต่โดยทั่วไปแล้วมีการใช้งานที่จำกัด อย่างไรก็ตาม มันเป็นปัญหาทั่วไปที่ครอบคลุมพื้นฐานของทุกแนวทาง การสร้างการเป็นตัวแทนไบนารี่แบบไม่มีเบาะสามารถทำได้ดังนี้:
/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
if (!v) { putchar ('0'); return; }; /* if v = 0 output '0' */
size_t sz = sizeof v * CHAR_BIT; /* get the number of bits in v */
unsigned long rem = 0; /* variable to hold shifted result */
while (sz--) /* for each bit (in decreasing order) */
if ((rem = v >> sz)) /* if bits exist in the shifted value */
putchar ((rem & 1) ? '1' : '0'); /* output '1' or '0' */
}
ความคิดเห็นค่อนข้างอธิบายได้ รูปแบบคือการเปลี่ยนแต่ละบิตที่ขึ้นต้นด้วยบิตที่สำคัญที่สุด (เช่น บิต 31 (31-0) สำหรับตัวเลข 32 บิต คุณตรวจสอบว่ามี 1 บิตใดๆ ที่ตามหลังการเปลี่ยนแปลงหรือไม่ (ถ้าไม่ใช่ การเปลี่ยนแปลงจะเกินค่าสูงสุด) ตำแหน่งบิตที่มีนัยสำคัญในตัวเลขและไม่จำเป็นต้องพิมพ์) เมื่อพบบิตใน rem
แล้ว ก็จะมีบิตบิตที่จะพิมพ์ตลอดส่วนที่เหลือของการวนซ้ำเนื่องจากคุณกำลังขยับตามจำนวนที่ลดลง โดยเริ่มจาก บิตที่สำคัญที่สุด (ซึ่งจะพิมพ์ก่อน) คุณจะจบลงด้วยบิตของคุณที่พิมพ์ออกมาตามลำดับที่ถูกต้องและพิมพ์เฉพาะจำนวนบิตที่ประกอบเป็นตัวเลขเท่านั้น
โดยทั่วไปเมื่อคุณเพียงแค่ส่งออกการเป็นตัวแทนไบนารี่ไปยังหน้าจอโดยตรง คุณจะต้องการส่งออกบิตจนถึงบิตที่สำคัญที่สุดเท่านั้น (ซึ่งป้องกันการส่งออก 1
โดยมี 63 0
อยู่ข้างหน้าทำให้เกิดความยุ่งเหยิง)
ถัดไป กำลังส่งออกการแทนค่าไบนารี่แบบบุนวมไปยังบิตจำนวนหนึ่ง สิ่งนี้มีประโยชน์ถ้าคุณต้องการดูที่ 8, 16, 32, ...
บิตล่างของตัวเลขใดๆ แต่ต้องการแสดงด้วยจำนวนบิตคงที่ในแต่ละครั้ง ที่นี่คุณเพียงแค่ส่งผ่านจำนวนบิตที่คุณต้องการดู ฟังก์ชันของคุณจะวนซ้ำตำแหน่งบิตจำนวนนั้นในตัวเลขของคุณและแสดงผลลัพธ์:
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
*/
void binprnpad (const unsigned long v, size_t sz)
{
if (!sz) putchar ((v & 1) ? '1' : '0'); /* if no sz, '0' is fine */
if (sz > sizeof v * CHAR_BIT) /* if sz exceed # of bits, limit */
sz = sizeof v * CHAR_BIT;
while (sz--) /* for sz positions in decreasing order, '1' or '0' */
putchar ((v >> sz & 1) ? '1' : '0');
}
คุณจะสังเกตเห็นความแตกต่างหลักที่นี่คือ คุณไม่ต้องกังวลกับการตรวจสอบว่ายังมีบิตเหลืออยู่หรือไม่เพื่อป้องกันการพิมพ์ศูนย์นำหน้าที่ไม่ต้องการ เนื่องจากคุณควบคุมจำนวนบิตด้วยพารามิเตอร์ sz
(ขึ้นอยู่กับคุณว่าคุณจะทำอย่างไรหากผ่านขนาด 0
ฉันแค่เลือกที่จะส่งออก '0'
)
ตอนนี้สำหรับประเด็นที่สามที่กล่าวถึงข้างต้น การส่งออกบิตเพียงอย่างเดียวนั้นยุ่งยากจากมุมมองการจัดรูปแบบในเนื้อหาหลักของโค้ดของคุณ ฉันพบว่ามีประโยชน์มากกว่ามากในการจัดเก็บบิตในอาร์เรย์อักขระ (สิ้นสุดด้วย nul เพื่อให้สามารถถือเป็นสตริงได้) และส่งคืนตัวชี้ไปยังอาร์เรย์เพื่อให้สามารถส่งผ่านไปยัง printf
ฯลฯ ตอนนี้คุณต้องส่งอาร์เรย์ที่มีขนาดเพียงพอเป็นพารามิเตอร์ ประกาศอาร์เรย์ static
เพื่อให้อาร์เรย์ไม่ถูกทำลายเมื่อส่งคืนฟังก์ชัน หรือจัดสรรพื้นที่เก็บข้อมูลแบบไดนามิกสำหรับอาร์เรย์ภายในฟังก์ชัน ทั้งหมดมีข้อดีและข้อเสียที่คุณต้องชั่งน้ำหนักโดยขึ้นอยู่กับความต้องการของโค้ดของคุณ เช่น.:
/** returns pointer to binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (const unsigned long v, const size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (v>>i & 1) ? '1' : '0';
return p;
}
โค้ดทำงานเหมือนกับโค้ดที่ไม่มีบัฟเฟอร์ด้านบน สังเกตว่า p
ส่งคืนตำแหน่งเริ่มต้น ภายใน บัฟเฟอร์โดยที่ sz
จำนวนบิตเริ่มต้นอย่างไร โปรดทราบว่าคุณจะต้องมีค่าคงที่สำหรับ BITS_PER_LONG
ซึ่งแสดงถึงจำนวนบิตใน long
บนฮาร์ดแวร์ของคุณ (ซึ่งปกติจะได้รับการจัดการในลักษณะคล้ายกับ BUILD_64
)
หมายเหตุ: โปรดทราบว่าข้อจำกัดประการหนึ่งของการประกาศ static
คือฟังก์ชันการแปลงสามารถใช้ได้เพียงครั้งเดียวในการเรียก printf
หนึ่งครั้ง (หรือภายในโค้ดบรรทัดเดียว) เนื่องจากมีอาร์เรย์หน่วยเก็บข้อมูลเพียงชุดเดียวสำหรับ การแปลงไบนารี (คุณสามารถโทรออกกี่ครั้งก็ได้และจัดเก็บผลลัพธ์ไว้ในตำแหน่งต่างๆ ก่อนที่จะโทร printf
)
รูปแบบสุดท้ายประการหนึ่งของการพิมพ์ไบนารี่คือการพิมพ์การแสดงด้วยตัวคั่นเพื่อให้ระบุและเปรียบเทียบระหว่างสตริงไบนารี่ได้ง่ายขึ้น (โดยเฉพาะเมื่อต้องจัดการกับลำดับที่ยาวกว่าของ 0
's และ 1
's เช่น:
hexval : 0xdeadbeef => 11011110-10101101-10111110-11101111
โดยพื้นฐานแล้วฟังก์ชันทำงานเหมือนกับ binpad
ข้างต้น แต่ด้วยการเพิ่มบัฟเฟอร์แบบคงที่ที่มีขนาดใหญ่กว่าเพื่อรองรับตัวแยกและการตรวจสอบเพิ่มเติมเกี่ยวกับตำแหน่งบิตเพื่อพิจารณาว่าเมื่อใดควรเพิ่มตัวแยกลงในบัฟเฟอร์:
/** returns pointer to formatted binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *binfmt (const unsigned long v, const unsigned char sz,
const unsigned char szs, const char sep)
{
static char s[BITS_PER_LONG * 2 + 1] = {0};
char *p = s + 2 * BITS_PER_LONG;
register size_t i;
*p = 0;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (v >> i & 1) ? '1' : '0';
}
return p;
}
ปัญหาที่เหลือของคุณคือเพียงประมวลผลอาร์กิวเมนต์บรรทัดคำสั่ง และทำการแปลงจากสตริงอินพุตเป็นค่าที่ไม่ได้ลงนาม พร้อมกับตรวจสอบความถูกต้องว่าจำนวนไม่เกิน 32 บิต ฯลฯ คุณสามารถประมวลผลอาร์กิวเมนต์ด้วย getops
หรือสำหรับตัวเลือกง่ายๆ จำนวนเล็กน้อย คุณสามารถใช้การวนซ้ำได้ บน Linux อาร์กิวเมนต์ที่จำเป็นเพียงอย่างเดียวที่โค้ดของคุณควรตอบสนองคือ -h
สำหรับความช่วยเหลือและ -v
สำหรับเวอร์ชัน แม้ว่าจะไม่มีใครทำสิ่งนี้เพื่อเป็นตัวอย่างสั้นๆ ฯลฯ แต่อย่างน้อยการมีข้อมูลนั้นก็ถือเป็นเรื่องดี ดูตัวอย่างต่อไปนี้ที่รวบรวมชิ้นส่วนทั้งหมดเข้าด้วยกัน และแจ้งให้เราทราบหากคุณมีคำถามใดๆ:
#include <stdio.h>
#include <stdlib.h> /* for strtoul */
#include <errno.h> /* for errno */
#include <limits.h> /* for UINT_MAX, ULONG_MAX, CHAR_BIT */
#define PACKAGE "hex2bin"
#define VERSION "0.01"
/* BUILD_64 - Check x86/x86_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
unsigned long processopts (int argc, char **argv);
unsigned long xstrtoul (char *s);
void binprn (const unsigned long v);
void binprnpad (const unsigned long v, size_t sz);
char *binpad (const unsigned long v, const size_t sz);
char *binfmt (const unsigned long v, const unsigned char sz,
const unsigned char szs, const char sep);
void help (int xcode);
int main (int argc, char **argv) {
unsigned long hexval = processopts (argc, argv);
/* print unpadded binary */
printf ("\n hexval : 0x%lx (%lu) => ", hexval, hexval);
binprn (hexval);
printf ("\n");
/* print padded to 32-bits */
printf ("\n hexval : 0x%lx (%lu) => ", hexval, hexval);
binprnpad (hexval, sizeof (int) * CHAR_BIT);
printf ("\n");
/* padded binary returned as formatted string
* with '-' separators every 8 bits
*/
printf ("\n hexval : 0x%lx (%lu) => %s\n\n", hexval, hexval,
binfmt (hexval, sizeof (int) * CHAR_BIT, CHAR_BIT, '-'));
return 0;
}
/* quick custom argument handler */
unsigned long processopts (int argc, char **argv)
{
size_t i = 1;
unsigned long val = 0;
if (argc < 2) help (0); /* insufficient arguments */
for (; argv[i]; i++) { /* for each argument */
if (*argv[i] == '-') { /* for each beginning with '-' */
switch (argv[i][1]) {
case 'h': /* respond to '-h' help */
help (0);
case 'p': /* handle '-p' convert value */
if (!argv[i+1]) { /* if '-p' w/o next arg */
fprintf (stderr, "error: insufficient input.\n");
help (1);
}
if (*argv[i+1] != '0' || /* validate hex input */
(argv[i+1][1] != 'x' && argv[i+1][1] != 'X')) {
fprintf (stderr, "error: invalid 'hex_value' input.\n");
help (1);
}
val = xstrtoul (argv[i+1]); /* convert to ulong */
if (val > UINT_MAX) { /* validate 32-bits */
fprintf (stderr, "error: input value exceeds 32-bits.\n");
help (1);
}
break;
case 'v': /* respond to '-v' version */
printf ("%s, version %s\n", PACKAGE, VERSION);
exit (0);
default :
fprintf (stderr, "error: invalid/unrecognized option '%s'.\n",
argv[i]);
help (1);
}
}
}
return val; /* return val */
}
unsigned long xstrtoul (char *s)
{
unsigned long v = 0;
errno = 0;
/* test for hex or decimal conversion */
if (*s == '0' && (s[1] == 'x' || s[1] == 'X'))
v = strtoul (s, NULL, 16);
else
v = strtoul (s, NULL, 10);
/* check for various possible errors */
if ((errno == ERANGE && v == ULONG_MAX) || (errno != 0 && v == 0)) {
perror ("strtoul");
exit (EXIT_FAILURE);
}
return v;
}
/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
if (!v) { putchar ('0'); return; };
size_t sz = sizeof v * CHAR_BIT;
unsigned long rem = 0;
while (sz--)
if ((rem = v >> sz))
putchar ((rem & 1) ? '1' : '0');
}
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
*/
void binprnpad (const unsigned long v, size_t sz)
{
if (!sz) putchar ((v & 1) ? '1' : '0');
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
/** returns pointer to binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (const unsigned long v, const size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (v>>i & 1) ? '1' : '0';
return p;
}
/** returns pointer to formatted binary representation of 'v' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *binfmt (const unsigned long v, const unsigned char sz,
const unsigned char szs, const char sep)
{
static char s[BITS_PER_LONG * 2 + 1] = {0};
char *p = s + 2 * BITS_PER_LONG;
register size_t i;
*p = 0;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (v >> i & 1) ? '1' : '0';
}
return p;
}
void help (int xcode)
{
xcode = xcode ? xcode : 0; /* set default exit code */
printf ("\n %s, version %s\n\n"
" usage: %s -p hex_value (32-bit)\n\n"
" converts 'hex_value' to its binary representation.\n\n"
" Options:\n\n"
" -h this help.\n"
" -p hex_value display binary representation of 'hex_value'.\n"
" -v display version information.\n\n",
PACKAGE, VERSION, PACKAGE);
exit (xcode);
}
ใช้/ส่งออก
$ ./bin/hex2bin -p 0xe7
hexval : 0xe7 (231) => 11100111
hexval : 0xe7 (231) => 00000000000000000000000011100111
hexval : 0xe7 (231) => 00000000-00000000-00000000-11100111
$ ./bin/hex2bin -p 0xdeadbeef
hexval : 0xdeadbeef (3735928559) => 11011110101011011011111011101111
hexval : 0xdeadbeef (3735928559) => 11011110101011011011111011101111
hexval : 0xdeadbeef (3735928559) => 11011110-10101101-10111110-11101111
$ ./bin/hex2bin -h
hex2bin, version 0.01
usage: hex2bin -p hex_value (32-bit)
converts 'hex_value' to its binary representation.
Options:
-h this help.
-p hex_value display binary representation of 'hex_value'.
-v display version information.
$ ./bin/hex2bin -v
hex2bin, version 0.01
person
David C. Rankin
schedule
19.02.2016
ยังไม่ชัดเจนว่าปัญหาของคุณคืออะไร อาจเป็นเพราะคุณมีแพ็คเกจบางอย่างที่ไม่เข้ากัน เพื่อหลีกเลี่ยงปัญหาประเภทนี้ ฉันขอแนะนำให้ใช้ Anaconda: https://anaconda.org
มันจะมาพร้อมกับ python และไลบรารีพื้นฐานส่วนใหญ่ รวมถึง matplotlib ฉันยังสามารถแนะนำ seaborn สำหรับแปลงที่ดูเป็นมืออาชีพที่ไม่ต้องใช้โค้ดมากนัก
- person DNH   schedule 19.02.20160-size
คุณจะได้รับบิตตามลำดับไบต์ของโฮสต์ ดังนั้นบิตแรกที่คุณเลื่อนจึงเป็นบิตที่มีนัยสำคัญน้อยที่สุดบนฮาร์ดแวร์ little-endian คุณสามารถจัดการได้หลายวิธี จัดทำดัชนีตำแหน่งอักขระในอาร์เรย์ของคุณจากสูงไปต่ำเพื่อแก้ไขปัญหา หรือคุณสามารถทำการเปลี่ยนแปลงที่ใหญ่ขึ้นก่อน (เช่นn >> size - 1
) แล้วเขียนบิตตามลำดับปกติ เมื่อคุณเข้าใจถึงนิสัยแปลกๆ แล้ว การเขียนโค้ดก็เป็นเรื่องง่าย - person David C. Rankin   schedule 19.02.2016