1

I am trying to learn how to write modern programs. I want to store binary data in strings and then output it. Why? For example I want to read a whole file to a string and then output it to stdout.

How can I do it? Printf and puts stop outputting data after the first \0

And what should I use to store filenames so I can work with international characters? wchar_t?

16
  • 4
    You shouldn't store binary data as a string, because of problems like \0 is the terminating string. Store the bytes in uint8_t arrays or unsigned char arrays, but do not treat them as strings. Also when you read a binary file, many bytes are just not printable and if you print them, you will get "garbage" on the screen. It's better to print the hex representation of the bytes. Commented Feb 20, 2018 at 23:53
  • 1
    no you can: printf("%.*s", str_len, str_ptr); Commented Feb 20, 2018 at 23:55
  • 2
    If you insist on printing gobbledygook to your terminal, (1) it's not actually a string, but (2) you can use fwrite to write arbitrary data to stdout as long as you remember how much data you have (because, again, it's not a string...there's no arbitrarydatalen function, and there can't be). Commented Feb 20, 2018 at 23:55
  • 1
    When dealing with binary stream, it's better to print them in hex format, and you can use printf for that: printf("%02x\n", val); Commented Feb 20, 2018 at 23:56
  • 3
    "How to use strings in C?" .. This is not how you use strings in C. Strings are character arrays of printable characters terminated with NUL, binary data does not have to fit that format at all. Commented Feb 20, 2018 at 23:57

2 Answers 2

3

Let's say you have a binary file. Let's say you want to read 8 bytes from the file.

FILE *fp = fopen("a", "rb");

if(fp == NULL)
    return;

unsigned char bytes[8];
if(fread(bytes, sizeof bytes / sizeof *bytes, 1, fp) != 1)
{
    fprintf(stderr, "could not read 8 bytes\n");
    return;
}

// printing the bytes:

for(size_t i = 0; i < sizeof bytes / sizeof *bytes; ++i)
    printf("%02X ", bytes[i]);

puts("");

fclose(fp);

I run this code reading the compiled binary (filename is a) of this same code, the first 8 bytes are:

7F 45 4C 46 02 01 01 00

As you can see there are bytes that have no representation and if I would print that as a string, this would be the result:

which is less helpful, here I was lucky that there were at least printable integers.

And if you want to have also the printable characters printed as as well (like hex editors do):

size_t n;
// yes I swapped the number of items and the number of bytes here
// for reading the whole file
while((n = fread(bytes, 1, sizeof bytes / sizeof *bytes, fp)))
{
    size_t i;
    for(i = 0; i < n; ++i)
        printf("%02X ", bytes[i]);

    // if less than array size bytes read, to align output
    printf("%*s", (int) ((sizeof bytes / sizeof *bytes) - i)*3, "");
    printf("%10s |", "");

    for(i = 0; i < n; ++i)
    {
        if(isprint(bytes[i])) 
            printf("%c", bytes[i]);
        else
            printf(".");
    }

    // same here as above
    printf("%*s", (int) ((sizeof bytes / sizeof *bytes) - i), "");
    puts("|");
}

This outputs:

7F 45 4C 46 02 01 01 00            |.ELF....|
00 00 00 00 00 00 00 00            |........|
03 00 3E 00 01 00 00 00            |..>.....|
A0 07 00 00 00 00 00 00            |........|
40 00 00 00 00 00 00 00            |@.......|
F0 23 00 00 00 00 00 00            |.#......|
00 00 00 00 40 00 38 00            |[email protected].|
09 00 40 00 23 00 22 00            |..@.#.".|
...
00 6C 69 62 63 2E 73 6F            |.libc.so|
2E 36 00 66 6F 70 65 6E            |.6.fopen|
00 70 75 74 73 00 5F 5F            |.puts.__|
73 74 61 63 6B 5F 63 68            |stack_ch|
6B 5F 66 61 69 6C 00 70            |k_fail.p|
75 74 63 68 61 72 00 70            |utchar.p|
72 69 6E 74 66 00 66 63            |rintf.fc|
6C 6F 73 65 00 5F 5F 63            |lose.__c|
74 79 70 65 5F 62 5F 6C            |type_b_l|
...
39 01 00 00 00 00 00 00            |9.......|
00 00 00 00 00 00 00 00            |........|
01 00 00 00 00 00 00 00            |........|
00 00 00 00 00 00 00 00            |........|
Sign up to request clarification or add additional context in comments.

3 Comments

Very good. Except fread(bytes, sizeof bytes / sizeof *bytes, 1, fp) != 1 may be better as fread(bytes, sizeof bytes, 1, fp) != 1.
@chux, I though of just doing sizeof bytes because sizeof *bytes is 1 anyway, but I wanted to have the correct way of having the number of elements of an array regardless of the type. If you think that the answer is more clear with having only sizeof bytes, let me know so that I can update the answer.
@Pablo Thanks. The first example is what I want. I need to send binary files to stdout so other programs can read these binary data from stdin.
1

I want to store binary data in strings and then output it.

Once you have your binary data in a storage (in our case it is char bin[]) you can make char ascii string out of it using sprintf :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

    int i;  
    char bin[] = { 0, 1 , '1', '2', '3' , 0 , 7 }; 
    char str[256]; 
    char *buf2 = str;

    size_t size =  sizeof(bin)*2;

    for(i= 0; i < size; i++  )
    {
        buf2 += sprintf(buf2, "%02X", bin[i]);
    }

    str[i] = 0; // terminate your string

    printf("STRING: %s", str);

    return 0;
}

Output:

STRING: 00013132330007

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.