Thread: Force variables to be stored in a char* array

  1. #1
    Registered User
    Join Date
    Jan 2015
    Posts
    8

    Question Force variables to be stored in a char* array

    I want to declare a char* array, and then make any future variables declared to be stored in a specific location within the char* array. Is this even possible, and if it is how would I go about doing it. (If it helps, I plan on storing any primitive data type in it (not classes or structs), and they may signed or unsigned)

  2. #2
    Registered User
    Join Date
    Dec 2013
    Posts
    241
    you can do it, but this is extremely stupid. what advantage will you get from it?

    Code:
    #include <iostream>
    
    int main (void){
        
        char* arr [sizeof(int) + sizeof(float)];
        
        int* a1 = (int*) &arr[0];
        *a1 = 4;
        
        float* a2 = (float*)&arr[sizeof(int)];
        *a2 = 5.443;
        
        printf ("%d\n%f",*a1,*a2);
        
        return 0;
    }
    (the only reason I did it is because I missed the nostalgic C pointers and minimalism , LOL)

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    One of several variations on a theme.
    Code:
    union overlay {
      struct mydata {
        int foo;
        double bar;
      } a;
      char b[sizeof(struct mydata)];
    };
    
    int main ( ) {
      union overlay d;
      d.a.foo = 1;
      d.a.bar = 2.3;
      return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by killer13666 View Post
    I want to declare a char* array, and then make any future variables declared to be stored in a specific location within the char* array. Is this even possible, and if it is how would I go about doing it. (If it helps, I plan on storing any primitive data type in it (not classes or structs), and they may signed or unsigned)
    Sure it's possible.

    Here's a rough outline to get you started
    Code:
    char* storage;
    size_t storage_off;
    
    int* new_int()
    {
        int* datum = (int*)(storage+storage_off);
        storage_off += sizeof(int);
        return datum;
    }

  5. #5
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    You guys are fast; two posts in the time it took me to write mine.

  6. #6
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    What problem are you trying to solve with this sort of solution? It seems overly complex, and I'm sure we can suggest a better option.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  7. #7
    Registered User
    Join Date
    Jan 2015
    Posts
    8
    I am trying to make a program that is similar to a virtual machine and an emulator put together, and it can only run one os (which will be hard-coded into to the program). The reason I wanted to do this is because it would be the easiest way to make sure that all variables in memory are in one contiguous block, that way the part that manages memory wouldn't have to store the locations of each variable (which would have been necessary for the virtual memory manager). If there are better ways than this, I am more than welcome to suggestions. By the way, thanks for the quick replies.

  8. #8
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Make sure you are aware of the strict aliasing rule if you are doing this.

    I believe most of the answers so far rely on undefined behaviour.

    Reading from a union through a member that wasn't last written to is also undefined behaviour if memory serves.

    The safest way is to use memcpy, because char* and void* are allowed to alias any memory. A smart compiler (eg. GCC last time I checked) will optimize it out and not actually call memcpy.

    Code:
    char a[1024];
    int b = 5;
    
    memcpy(a + 4, &b, sizeof(int));
    You'll also have to think about alignment. Many architectures don't allow unaligned access (reading a 4 byte variable from an address that's not a multiple of 4), or have performance penalty for unaligned access.

  9. #9
    Registered User
    Join Date
    Jan 2015
    Posts
    8
    Quote Originally Posted by cyberfish View Post
    The safest way is to use memcpy, because char* and void* are allowed to alias any memory. A smart compiler (eg. GCC last time I checked) will optimize it out and not actually call memcpy.

    Code:
    char a[1024];
    int b = 5;
    
    memcpy(a + 4, &b, sizeof(int));
    Using your example, would I still be able to use the variable name 'b' to access it, or would I have to know it's location within 'a' and make a pointer to it.

  10. #10
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Quote Originally Posted by killer13666 View Post
    Using your example, would I still be able to use the variable name 'b' to access it, or would I have to know it's location within 'a' and make a pointer to it.
    You would have to use memcpy to copy it out to an int when you need to access it, otherwise you run into the same aliasing problem.

  11. #11
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I swear I had an interview question like this once, using a char buffer for storage. I think one solution I got from here was to use placement new() as well. I'm not sure if it'll work for primitive types but I think it was the solution for structured/class types.

    Edit : Does this violate the aliasing rules cyber mentioned?

    Code:
    #include <iostream>
    
    
    struct pair
    {
        int first, second;
    };
    
    
    template<typename T>
    T* push_back(char *buffer,
                 int  &back,
                 T     value)
    {
        T *data = new(buffer + back) T(value);
        back += sizeof(T);
    
    
        return data;
    }
    
    
    template<typename T>
    T* push_back(char *buffer,
                 int  &back)
    {
        T *data = new(buffer + back) T();
        back += sizeof(T);
    
    
        return data;
    }
    
    
    int main(void)
    {
        const int buffer_size = 1024;
    
    
        char buffer[buffer_size];
        int back = 0;
    
    
        int *int_val = push_back<int>(buffer, back, 10);
    
    
        pair *pair_val = push_back<pair>(buffer, back);
    
    
        pair_val->first = 20;
        pair_val->second = 35;
    
    
        std::cout << *int_val << std::endl;
        std::cout << pair_val->first << std::endl;
        std::cout << pair_val->second << std::endl;
    }
    Edit edit : This compiled quietly with "-std=c++11 -Wall -Wextra -pedantic -O3"
    Last edited by MutantJohn; 01-08-2015 at 01:50 PM.

  12. #12
    Registered User
    Join Date
    Jan 2015
    Posts
    8
    Quote Originally Posted by MutantJohn View Post
    I swear I had an interview question like this once, using a char buffer for storage. I think one solution I got from here was to use placement new() as well. I'm not sure if it'll work for primitive types but I think it was the solution for structured/class types.
    This works perfectly, thank you. It works fine with primitive types.

    Quote Originally Posted by cyberfish View Post
    You'll also have to think about alignment. Many architectures don't allow unaligned access (reading a 4 byte variable from an address that's not a multiple of 4), or have performance penalty for unaligned access.
    I figured unaligned access was going to be a problem, and I planned on making sure every thing was properly aligned.

    Again, thank you all for the help, I appreciate it immensely.

  13. #13
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Quote Originally Posted by MutantJohn View Post
    I swear I had an interview question like this once, using a char buffer for storage. I think one solution I got from here was to use placement new() as well. I'm not sure if it'll work for primitive types but I think it was the solution for structured/class types.

    Edit : Does this violate the aliasing rules cyber mentioned?

    Code:
    #include <iostream>
    
    
    struct pair
    {
        int first, second;
    };
    
    
    template<typename T>
    T* push_back(char *buffer,
                 int  &back,
                 T     value)
    {
        T *data = new(buffer + back) T(value);
        back += sizeof(T);
    
    
        return data;
    }
    
    
    template<typename T>
    T* push_back(char *buffer,
                 int  &back)
    {
        T *data = new(buffer + back) T();
        back += sizeof(T);
    
    
        return data;
    }
    
    
    int main(void)
    {
        const int buffer_size = 1024;
    
    
        char buffer[buffer_size];
        int back = 0;
    
    
        int *int_val = push_back<int>(buffer, back, 10);
    
    
        pair *pair_val = push_back<pair>(buffer, back);
    
    
        pair_val->first = 20;
        pair_val->second = 35;
    
    
        std::cout << *int_val << std::endl;
        std::cout << pair_val->first << std::endl;
        std::cout << pair_val->second << std::endl;
    }
    Edit edit : This compiled quietly with "-std=c++11 -Wall -Wextra -pedantic -O3"
    Sorry I missed this post for some reason.

    From my research it seems like there is an exception in the strict aliasing rule for placement new (it changing the dynamic type of the memory block), which makes sense since otherwise there would be no safe way to use placement new.

    Help for building or using GCC
    [The] C++ aliasing rules are not the same as the C
    aliasing rules. In C++, if you use placement new, it changes the
    dynamic type of the memory location. The memory location must then be
    accessed using that type, until a new placement new is run, or the
    memory is modified using the original type.
    Using 2 placement new for 2 different types on the same location would result in undefined behaviour. I believe (but I'm not sure) what that means is once you do placement new, you have to assume the memory is uninitialized, even if you knew what's supposed to be in there before placement new.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. converting int stored in array to char?
    By Meerul264 in forum C++ Programming
    Replies: 1
    Last Post: 12-24-2012, 08:31 AM
  2. Can anyone explain to me how are variables stored?
    By jonez334 in forum C++ Programming
    Replies: 1
    Last Post: 10-15-2012, 09:55 PM
  3. dealing with ints stored in char variables
    By Maga in forum C Programming
    Replies: 7
    Last Post: 02-26-2010, 02:46 AM
  4. Replies: 3
    Last Post: 11-28-2006, 03:44 PM
  5. Hex digits stored in char array.
    By Kevinmun in forum C Programming
    Replies: 8
    Last Post: 11-18-2005, 04:05 PM

Tags for this Thread