-3

I'm struggling with a really weird situation that I can't explain.
Basically I don't understand why results of modulus or division between two hex numbers are wrong (I'm using C).

I have a variable time which is a 32bit unsigned int and it's initialized to 0 and then other two 32bit unsigned ints, div and res, both initialized to 0 too.

if (time > 0x1388) {
    div = time / 0x1388;
    res = time - (0x1388 * div);
}

This chunk of code should act as the modulus operator between time and 0x1388. Time is a variable which gets incremented all around my program and when it's value is greater than 0x1388, I need its remainder to do other calculations.

This is an example of calculated value that are wrong... Let's suppose time is 0x1770, which is greater than 0x1388. The division between 0x1770 and 0x1388 should be 0x1 (div) with a reminder of 0x3E8 (res). The problem is that after executing this code, div is always 0x0FFFFF instead of 0x1 and res gets a really weird value.

I already tried to use the modulus but the result is the same. Can someone explain me what's going on?
Maybe is it related to the fact that I'm using unsigned ints? If so, can you please tell me what operations I need to be careful of when using unsigned ints?

EDIT: Trying to add some more code...
file1.c

unsigned int res = 0, div = 0, time = 0; // global variables
unsigned int valueChecker() {
    if (time > 0x1388) {
        div = time / 0x1388;
        res = time - (0x1388 * div);
    }
    return res;
}

This function is called periodically after a specific amount of time

fileB.c

extern unsigned int time;

void calculate() {
    // do some stuff
    time += getHEXTime(); // this function has been supplied and return time as an HEX number
    // do other stuff
}

This function is called by the main several times, between other calculation (which doesn't involve time, div or res).

I'd be so grateful if someone can help me!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
matteodv
  • 3,992
  • 5
  • 39
  • 73
  • 2
    Would you mind posting a [Minimal, *Complete*, and Verifiable example](http://stackoverflow.com/help/mcve)? – MikeCAT Sep 14 '16 at 23:43
  • 2
    The C standard library has functions `time` and `div`, so my first attempt will be using another names, not knowing whether it will work. – MikeCAT Sep 14 '16 at 23:45
  • Thanks for your comments... I don't use time and div var names and I don't think there are conflicts because I'm not using C standard library. It's just bare C code thank have to be executed on a ARM emulator. – matteodv Sep 14 '16 at 23:48
  • For the example, it's quite difficult to post one... Maybe I can try to explain... The chuck of code above is in a function that gets executed after a specific amount of time. Time instead, is a global variable which keeps track of the lifetime of a data structure and gets updated every time a function is called. The time between the last call and the new one is added to time. Think that variable as a shared counter which gets incremented; when it's value is greater than 0x1388, I have to calculare the reminder. – matteodv Sep 14 '16 at 23:56
  • 1
    Either your compiler has a bug, or there's something you aren't telling us (hence the need for a [minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve)). Both the code you've shown, and the modulus operator, should work. – user3386109 Sep 14 '16 at 23:56
  • Are you sure you don't have to calculate the reminder when the value is exactly 0x1388? – MikeCAT Sep 14 '16 at 23:57
  • E.g. one possibility is that your real code is `if (gettime() > 0x1388) div=gettime() / 0x1388;` In that case, the time that the `if` statement sees is not necessarily the same as the time that the division sees. – user3386109 Sep 15 '16 at 00:01
  • Try using `0x1388U` so you get an unsigned literal, not signed. – Barmar Sep 15 '16 at 00:06
  • @user3386109 That wouldn't explain getting a result like `0x0ffffff`. – Barmar Sep 15 '16 at 00:08
  • Thank you so much for all your comments, I'm gonna try every suggestion... The reminder need to be calculated when time's value is greater than 0x1388. – matteodv Sep 15 '16 at 00:09
  • @barman, yes, exactly! I don't exaplin a result like 0xFFFFF... I also checked values step by step but it acts like that :/ – matteodv Sep 15 '16 at 00:11
  • Does it work correctly if you use decimal literals instead of hex? Have you looked at the generated assembly code to see what it's actually doing? – Barmar Sep 15 '16 at 00:12
  • Just tried using 0x1388U, decimal literal (5000) but nothing changes... div is always 0xFFFFF and res is 0xC7802823... Unfortunately I don't know how to look at the assembly code :( – matteodv Sep 15 '16 at 00:20
  • 1
    It causes undefined behaviour to make a global variable with the same name as a standard library function, even if you didn't include that standard header. Change the names and try again – M.M Sep 15 '16 at 00:21
  • Changed to timeLife, divisor and reminder but nothing changes... Furthermore, if I use simple operations like sum or difference or multiplication, I don't have any problems – matteodv Sep 15 '16 at 00:25
  • "This chunk of code should act as the modulus operator between time and 0x1388" --> No, not quite. `if (time > 0x1388) {` should be `if (time >= 0x1388) {` for modulus. – chux - Reinstate Monica Sep 15 '16 at 01:15
  • "`div` is always 0x0FFFFF instead of 0x1 and res gets a really weird value." --> 1) posting the code or method used to determine this would help as _that_ could be at fault - or casuing the problem. 2) Was that `div` is always 0x0FFFFF or `div` is always 0x0FFFF? 3) I have doubts that all the _facts_ are as presented. Posting a minimal code that demos the problem is critical to arriving at a solution. – chux - Reinstate Monica Sep 15 '16 at 01:21
  • "`res` gets a really weird value." is not as useful as posting the value(s) it does get. – chux - Reinstate Monica Sep 15 '16 at 01:23
  • 1
    Res is 0xC7802823, div is 0x0FFFFF. The code is really like that one, and these variables are just used in that two functions... and sorry for the delayed responses since here where I live is so late :) – matteodv Sep 15 '16 at 01:26
  • How did you determine the values of `res,div`? You have yet to post that. BTW :`div` is the name of a function `div_t div(int numer, int denom);` You may want to try your code using a different name in case there is some odd interaction. Same for `time`, choose a new name. – chux - Reinstate Monica Sep 15 '16 at 04:13
  • I wondering if the `time` in `valueChecker()` is getting the address of the function `time()` rather than your global variable `time`. After all, you did say "div is _always_ 0x0FFFFF" implying a constant value for `time`. Try a name like `g_time` for your global time variable. Perhaps your linker is confused or mis-directed? Hmm Now I see @MikeCAT comment - oh well. – chux - Reinstate Monica Sep 15 '16 at 04:24
  • Already tried changing variables names, now called timeLife, reminder and divider but nothing changes. The value of div is 0x0FFFFF just after executing the if statement for the first time. I check his value using a Structure Viewer from the emulator, which is uARM http://mellotanica.github.io/uARM/ – matteodv Sep 15 '16 at 07:08

1 Answers1

1

Using the following program I get good output:

#include <stdio.h>

unsigned int res = 0, div = 0, time = 0x1300; // global variables
unsigned int valueChecker() {
    if (time > 0x1388) {
        div = time / 0x1388;
        printf( "Div: %u\n", div );
        res = time - (0x1388 * div);
        printf( "Mod: %u\n", res );
    }
    return res;
}

int main(void) {
    while( time < 0x1390 )
    {
        time += 1;
        valueChecker();
    }
    return 0;
}

Output:

Div: 1
Mod: 1
Div: 1
Mod: 2
Div: 1
Mod: 3
Div: 1
Mod: 4
Div: 1
Mod: 5
Div: 1
Mod: 6
Div: 1
Mod: 7
Div: 1
Mod: 8

This means that the problem is most likely with extern unsigned int time. To try and fix this problem do the following:

Make sure your internal globals are declaired as static so no other modules can accidentally modify them:

static unsigned int res = 0;
static unsigned int div = 0;

Make sure all multi-unit symbols have a very very unique name, just in case:

unsigned int global_hexTime = 0;

When I do the following:

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

extern unsigned int time;
/* i had to rename div because it was already in stdlib.h! */
static unsigned int res = 0, divisor = 0; // global variables
unsigned int valueChecker() {
    if (time > 0x1388) {
        divisor = time / 0x1388;
        printf( "Div: %u\n", divisor );
        res = time - (0x1388 * divisor);
        printf( "Mod: %u\n", res );
    }
    return res;
}

int main(void) {
    int i = 0;
    while( i < 100 )
    {
        i += 1;
        valueChecker();
    }
    return 0;
}

I get very bad output:

Div: 510868
Mod: 863
Div: 510868
Mod: 863
Div: 510868
Mod: 863
Div: 510868
...

This problem is definitely with the external import and use of global symbols. Make sure you always read and fix Warnings as well.

Serdalis
  • 10,296
  • 2
  • 38
  • 58
  • In the 'bad' example, I think the problem is related to the fact that there's no formal definition (as opposed to declaration) of the global variable `time`, so in fact the system library function `time` is providing the value. And you can't change the location of the function, so ... things go weird. When you explicitly define the variable `time`, you get sane behaviour. – Jonathan Leffler Sep 15 '16 at 02:30
  • @JonathanLeffler That is true, In my GCC examples with a `time` variable I did get sane behaviour. But I thought it worth mentioning since I don't know what his environment is like or how he is compiling / linking his modules. I can't think of any other reason apart from symbol clashes in his program that would display the behaviour he discribes from the examples though. – Serdalis Sep 15 '16 at 02:37