Home > Mobile >  Is it possible to cast a string into its integer/long representation in C?
Is it possible to cast a string into its integer/long representation in C?

Time:04-24

Upon decompiling various programs (which I do not have the source for), I have found some interesting sequences of code. A program has a c-string (str) defined in the DATA section. In some function in the TEXT section, a part of that string is set by moving a hexadecimal number to a position in the string (simplified Intel assembly MOV str,0x006f6c6c6568). Here is an snippet in C:

#include <stdio.h>

static char str[16];

int main(void)
{
    *(long *)str = 0x006f6c6c6568;
    printf("%s\n", str);
    return 0;
}

I am running macOS, which uses little endian, so 0x006f6c6c6568 translates to hello. The program compiles with no errors or warnings, and when run, prints out hello as expected. I calculated 0x006f6c6c6568 by hand, but I was wondering if C could do it for me. Something like this is what I mean:

#include <stdio.h>

static char str[16];

int main(void)
{
    // *(long *)str = 0x006f6c6c6568;
    *(str 0) = "hello";
    printf("%s\n", str);
    return 0;
}

Now, I would not like to treat "hello" as a string literal, it might be treated like this for little-endian:

    *(long *)str = (long)(((long)'h') |
                          ((long)'e' << 8) |
                          ((long)'l' << 16) |
                          ((long)'l' << 24) |
                          ((long)'o' << 32) |
                          ((long)0 << 40));

Or, if compiled for a big-endian target, this:

    *(long *)str = (long)((0 |
                          ((long)'o' << 8) |
                          ((long)'l' << 16) |
                          ((long)'l' << 24) |
                          ((long)'e' << 32) |
                          ((long)'h' << 40));

Thoughts?

CodePudding user response:

is there some built-in C function/method/preprocessor function/operator/etc. that can convert an 8 character string into its raw hexadecimal representation of long type

I see you've already accepted an answer, but I think this solution is easier to understand and probably what you want.

Copying the string bytes into a 64-bit integer type is all that's needed. I'm going to use uint64_t instead of long as that's guaranteed to be 8 bytes on all platforms. long is often only 4 bytes.

#include <string.h>
#include <stdint.h>
#include <inttypes.h>

uint64_t packString(const char* str) {
    uint64_t value = 0;
    size_t copy = str ? strnlen(str, sizeof(value)) : 0; // copy over at most 8 bytes

    memcpy(&value, str, copy);
    return value;
}

Example:

int main() {
    printf("0x%" PRIx64 "\n", packString("hello"));
    return 0;
}

Then build and run:

$:~/code/packString$ g main.cpp -o main

$:~/code/packString$ ./main

0x6f6c6c6568

CodePudding user response:

Add #if __BYTE_ORDER__ to judge, like this:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    *(long *)str = (long)(((long)'h') |
                          ((long)'e' << 8) |
                          ((long)'l' << 16) |
                          ((long)'l' << 24) |
                          ((long)'o' << 32) |
                          ((long)0 << 40));
#else
    *(long *)str = (long)((0 |
                           ((long)'o' << 8) |
                           ((long)'l' << 16) |
                           ((long)'l' << 24) |
                           ((long)'e' << 32) |
                           ((long)'h' << 40));
#endif
  • Related