Thread: Assigning a new, discrete value to a pointer

  1. #1
    Registered User
    Join Date
    Aug 2016
    Posts
    9

    Assigning a new, discrete value to a pointer

    I haven't been able to find a full solution to this issue yet, so I started an account here in the hope that I could get some help. I'm not a frequent C programmer, so if I've made some fundamental mistakes then I apologize.

    I'm trying to set up a portion of my program that can read a value from a particular memory address. However, I want the user (me) to be able to modify the memory location being read, so I can access various memory segments at will. In other words, I tell the software what address I want, and it either modifies the value at that memory location or it spits out the value stored at that memory location.

    It's easy in Assembly; I just dump the desired address into the index register and then do my thing, but I can't seem to make the pointers work out right in C.

    Using my awesome knowledge of pointers, I tried this, but it failed miserably:

    Code:
    void partOfMyCode(void)
    {
        unsigned long a1;
        unsigned long v1;
    
        a1 = 0x0000C762;
    
        v1 = *a1;
    }
    I really, honestly thought this would work, because I thought that the * operator generated a reference to the following address. So, then I tried this, thinking it was something with the way the compiler was interpreting my code:

    Code:
    void partOfMyCode(void)
    {
        unsigned long v1;
    
        v1 = *0x0000C762;
    }
    I was certain that was going to work, because the compiler couldn't possible be misunderstanding me. Nope. More failure. So, I did as much research as I could, and now I can do this, where I hard-code the address at design-time, and it works:

    Code:
    void partOfMyCode(void)
    {
        unsigned long *p1;
        unsigned long v1;
    
        p1 = (unsigned long *)0x0000C762;
    
        v1 = *p1;
    }
    However, this doesn't work:

    Code:
     void partOfMyCode(void)
    {
        unsigned long *p1;
        unsigned long a1;
        unsigned long v1;
    
        a1 = 0x0000C762;
    
        p1 = (unsigned long *)a1;
    
        v1 = *p1;
    }
    In the long run, as I mentioned, I want to be able to adjust the value of a1 on the fly through a user input (which just takes an integer argument), and then have the software either write to or read from that specific address. In other words, at some point I want to have

    Code:
    {
        a1=someUserInput;
    
        {working code here}
    
        someUserOutput = valueAtA1;
    }
    Any help is much appreciated.

    Matt

  2. #2
    Registered User
    Join Date
    Feb 2012
    Posts
    347
    Code:
    #include <stdio.h>
    int main(void)
    {
        int a;
        int *p1;
        printf("Pls enter the address\n");
        scanf("%d", &a);
        p1 = (int *)a;
        printf("p1 = %p, a = %d\n",(void *)p1,a);
        return 0;
    }
    output
    Code:
    Pls enter the address
    89023
    p1 = 0x15bbf, a = 89023
    The above code works fine for me.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    On most modern machines, those running protected operating systems, you can't just invent addresses and go snooping.

    What are you intending this code to run on?
    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
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    Thanks for the responses. I should have explained, because my request in most worlds like like asking someone to hold a seance with the devil himself.

    My code is for an embedded system, with a PC interface (or smartphone interface, or whatever). There is no operating system. I'm in the development stage, where the memory map is constantly changing. I don't want to have to re-write all the code that assigns the variables I poll, set, and plot each time the map changes, so for now I just reference the memory map and plop those values into my PC program. The PC program then sends a communication to the DSP over some communication port (UART for now), and the DSP takes the transmitted address and manipulates the variable at that location accordingly. I promise I'm not being careless here, and it's all for my personal use until we get to the point where the memory map stops changing so much with each version.

    So, as I understand it, I need to dereference the variable that stores the address when the DSP recieves it, is that correct? Something like this:

    Code:
     void partOfMyCode(void)
    {
        unsigned long *p1;
        unsigned long a1;
        unsigned long v1;
    
        &a1 = 0x0000C762;
    
        p1 = (unsigned long *)a1;
    
        v1 = *p1;
    }

    Unfortunately, I'm leaving Mexico right now, and I've already packed up the system. I won't be set up again for a couple weeks, but I'm eager to give it a shot.

    Thanks again for the help.

    Matt

  5. #5
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    OK, so I'm back from Mexico and I have the system set up at work. I realize the previous post was stupid; one can't dereference the value on the left, because in effect &a1 is the address for the variable a1, if I understand correct.

    However, I'm still having trouble with this, and I can't find much of anything written about the subject, probably because direct memory access is taboo in most places.

    So, I'd like to know if anyone can see what I'm doing wrong. I see no effective difference between what I am doing and what Satya proposed. We both define an address pointer and a variable to accept the target address from the user. We both load an address into the temporary variable, and then assign the pointed-to location to the pointer. He spits the pointed-to value out to a console, while I transfer it to a secondary variable (ultimately this will be to a WiFi network, or Bluetooth interface, or something like that). However, the end variable doesn't have the right value. I'm able to check, both with the debugger and also by dumping a stored data log to my PC.

    Again, when I use

    Code:
      p1 = (unsigned long *)0x0000C762;
    
      v1 = *p1;
    I get the right value in v1. But, when I try to transfer the address through an intermediate variable, v1 isn't correct:

    Code:
      a1 = 0x0000C762;
    
      p1 = (unsigned long *)a1;
    
      v1 = *p1;
    I know I'm not getting the right values, because the address in question is the DC bus voltage. I'm simultaneously plotting the DC bus in a hard-coded variable. The first code example gives me 500 data points where the two logs are identical. The second gives me a bunch of nonsense in the second log.

    This makes me wonder: Satay, how do you know you're getting the correct value reported to the console?

    Thanks again for any feedback. I'm really at a complete loss here.

    Matt
    Last edited by meiermat; 08-18-2016 at 08:46 AM.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    So what type is a1 in your 2nd example?

    You need a type which is at least as big as a pointer on your machine.
    Verify that
    sizeof(unsigned long) >= sizeof(void*)

    Say for example
    unsigned long a1 = 0x0000C762UL;
    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.

  7. #7
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    Those were just copies from the examples in the original post. The pointer is type unsigned long, which in this case points to a 32-bit value. The two variables are also 32-bits (also unsigned long). Pointers themselves are 32 bits, but apparently the compiler assumes all variables and functions have addresses below 22 bits. At any rate, this should be OK.

    What is the purpose od UL at the end of the second line there? Is that some alternate method for typecasting?

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Without a suffix, a numeric constant is assumed to be of type int.
    If int happens to be say 16 bits on your machine, then you could be silently losing the high word of the value.

    UL forces the constant itself to have a type of unsigned long to begin with, so nothing is lost on assignment to an unsigned long.
    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.

  9. #9
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    That's really interesting to know. I suppose this particular compiler is an anomaly, as it takes 32-bit numeric constants, even though int is only 16 bits. Even so, adding the UL at the end doesn't change the behavior.

    However, I "found" what's wrong, and I'm wondering if maybe this is a compiler error? I'll need to post more of my overall code to explain, but basically, my original attempt does work in some cases I found this completely on accident, when I was checking the size of the pointer and integers.

    Here's the required code, which doesn't work. _iq is a proprietary data type, which is nothing more than a 32-bit integer. It's declared as _iq for the compiler, which uses a library for fixed-point arithmetic.

    Code:
    _iq storedData1[500];
    _iq storedData2[500];
    unsigned long storedDataIndex = 0;
    unsigned long gAdcData.dcBus;//This is the variable I'm trying to plot
    
    void mainIsr(void)
    {
      unsigned long *p1;
      unsigned long a1;
    
      if (storedDataIndex < 500)
      {
        //0x0000C732 is the address of the variable gAdcData.dcBus
        a1 = 0x0000C732UL;
        p1 = (unsigned long *)a1;
        storedData1[storedDataIndex] = *p1;
        storedData2[storedDataIndex] = gAdcData.dcBus;
      }
    }
    Then, when I was checking the integer sizes, I replaced gAdcData.dcBus with sizeof(void*). All of the sudden, the first array was logging the DC bus. Then, when I put gAdcData.dcBus back in, all I got was zeroes for the first array. I found that, if I log gAdcData.dcBus before using the direct address method, everything is fine. However, when I try to log it AFTER the direct address section, all I get are zeroes for the array that uses the direct address method. Moreover, when I replace gAdcData.dcBus with another variable, everything is fine. However, when I try to direct-address that other variable, it doesn't work right. Separating them into different sections of the main loop doesn't help, only the order that I reference the variable. It's like the compiler is optimizing something out, but I have all optimizations turned off.

    Any thoughts? I've found issues with this compiler before (which have been confirmed by the manufacturer), so it's not entirely infallible.

    Thanks again for all the help.

    Matt

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Compilers provided by manufacturers for specific embedded processors can be buggier than more mainstream compilers (I too have found several bugs in such compilers in the past).

    If you can, simplify the test case a bit more, then look at the generated assembler for both cases. With only a few lines of C, it's fairly easy to match that up generated asm with the source.

    Only then will you be able to confirm that the compiler is making a mess of the translation. My guess would be in the bad case, it either missed out a 'load' altogether, or it only performed a 16-bit load instead of a 32-bit load. Another possibility is it does the reading of the bus fine, but messes up the store.

    Then you should have a good test case to report back to the manufacturer.
    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.

  11. #11
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    That's about what I figured. I'll work out some examples and send them in tonight.

    I do have one more question, that I expect you'll be able to answer given your avatar. I've searched for a reason that void main(void) is bad, and here's what I've found (including a good explanation on this site):

    1. Your operating system expects the program to return an integer
    2. It's just the standard, so that's how you should do it

    I can respect the need for a standard, and I understand that the standard probably followed from the expectation of the operating system. But, the root rationale doesn't entirely make sense to me. Why does the OS expect a returned value? Is it just that this is the way many OSes developed, and so we must write software to accommodate them? What does it do with the value that's returned? If I send it a non-zero number, I've read that the OS interprets this as an error, but what does it do with that error? I don't expect it will put the program on probation...

    Mostly just curious, because EVERY C program I've seen uses void main(void).

    Matt

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    The requirement to return an int only applies to hosted environments, where your typical program is invoked (indirectly) from a shell of some kind.

    By returning an int, a program can indicate to the calling process whether it was successful or not.
    Code:
    ./myprog file.txt
    # $? is a shell variable containing the value passed to exit(), or the value passed to return
    # in the main() of the program.
    if [ $? -eq 0 ]; then 
      # success, do the next thing
    else
     # failed, bail and complain, or try something else
    fi
    A long time ago, I was using a rather nice program (in terms of features), but the programmer had elected to return 'void' instead of 'int'.
    So instead of having a nice clean status to work with, $? contained garbage, and I had to resort to all sorts of parsing of stdout and stderr to figure out whether it was success or fail.

    Historically on DOS, the OS was barely capable of running one program, and no one cared whether it returned a meaningful status, since nothing was around to look. Mostly people ran their program then switched the machine off. In this environment, void main gained traction.

    But people who wrote programs for Unix-like and POSIX systems generally did so knowing that their programs could readily be used as part of a program suite, and thus making sure their programs returned a proper status was second nature to them.

    Now your environment is a free-standing environment (actually, I would contend that DOS is a free-standing environment as well).
    Freestanding vs. hosted implementations | Embedded
    Basically, you read your compiler manual to find out how to declare main, or even whether the program entry point has a different name altogether. The program isn't really portable outside of the environment it was created for.
    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.

  13. #13
    Registered User
    Join Date
    Aug 2016
    Posts
    9
    OK, that makes complete sense. I just couldn't figure out what would happen if Windows got the wrong number back. I hadn't considered software that was nested and called by other software.

    Thanks again for everything. It's been very helpful.

    Matt

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Assigning value during pointer declaration
    By pkumarn in forum C Programming
    Replies: 8
    Last Post: 08-31-2013, 11:42 AM
  2. Assigning value to char pointer
    By Ducky in forum C Programming
    Replies: 3
    Last Post: 02-03-2013, 07:26 AM
  3. Assigning Array to Pointer?
    By Ditrik in forum C Programming
    Replies: 4
    Last Post: 01-10-2010, 08:04 AM
  4. Assigning a pointer a value -- Still = 0?
    By rjg32 in forum C Programming
    Replies: 1
    Last Post: 02-05-2009, 12:16 AM
  5. Assigning to Void Pointer
    By coder8137 in forum C Programming
    Replies: 7
    Last Post: 12-06-2006, 01:38 PM

Tags for this Thread