Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Tue Jul 02, 2013 6:36 pm UTC

I guess they box it as an alternative to calling .ToString()

Code: Select all

int i = 0;
string str = "test" + i;
will throw an exception. I'm guessing the cast prevents it.
Image

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5101
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Tue Jul 02, 2013 6:42 pm UTC

I didn't think that code threw any exceptions in Java. It definitely doesn't in C#.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Tue Jul 02, 2013 6:44 pm UTC

Wait... wrong .NET language.
Curse you VB!
Image

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Tue Jul 02, 2013 6:56 pm UTC

sparkyb wrote:
EvanED wrote:Did you see how much memory it was taking up? Did it go on a spree where for some reason it was allocating more and more memory instead of crashing?


It isn't allocating any memory, it is just writing into unallocated (at least not to it) memory. There's a decent chance it would crash, but it depends on what is in memory after it
By "allocating" I meant actually mapping pages from the OS, not in the malloc sense of allocating. What "should" have happened (in the absence of a nul byte) is that before long it'd have hit a page boundary where the next page was unmapped, at which point it would crash. I was wondering if, when it hit an unmapped page, it was actually being allocated that page by the OS instead.

This is what happens with the stack. When the program pushes a new stack frame, if it spills over onto an unmapped page then when the program actually writes to that page the operating system will notice it's adjacent to the existing stack and will automatically map it. This makes it possible for a program to avoid preallocating the entire stack or checking whether the stack is big enough every time it needs to grow. It is also why at least MSVC inserts page guard checks (possibly GCC needs something like it to, but I don't know what happens on Linux as well) when you have a function with a frame that is bigger than one page. Suppose that you had a frame that was two pages in size, and you wrote at the top of it (away from the caller frame). Then you'd be writing to an unmapped page that is not adjacent to the existing stack, which at least Windows considers an error and will give you a page fault.

However, OSs cap the growth of the stack size in this way. On Windows it's a property of the executable (it's specified in the PE header and you can set it with a linker flag or change it after-the-fact with editbin); on Linux it's a more global property you can set with ulimit (though you can probably also specify it with some API call).

So my best guess was that the stack was growing indefinitely, forcing the machine to continue allocating and perhaps even forcing it to page (which every OS handles badly and Windows handles worse). That still leaves open questions of course (e.g. nul bytes), but I couldn't think of any other reason. It sounds like that's not the cause though, so I have no clue what happened.

User avatar
phlip
Restorer of Worlds
Posts: 7573
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Jul 03, 2013 1:21 am UTC

Does that happen in both directions, though? IIRC the x86 stack extends backwards, so when it needs to allocate a new stack page, it will be at a lower address than the existing stack... whereas this code is counting into the increasing values.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
chridd
Has a vermicelli title
Posts: 846
Joined: Tue Aug 19, 2008 10:07 am UTC
Location: ...Earth, I guess?
Contact:

Re: Coding: Fleeting Thoughts

Postby chridd » Wed Jul 03, 2013 1:41 am UTC

Could it have corrupted the return address to point to some code that allocates a lot of memory (or perhaps starts other processes in an infinite loop)? Or perhaps corrupted a variable that's passed to malloc at some later point in the program?
~ chri d. d. /tʃɹɪ.di.di/ (Phonotactics, schmphonotactics) · she · Forum game scores
mittfh wrote:I wish this post was very quotable...

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Wed Jul 03, 2013 2:00 am UTC

phlip wrote:Does that happen in both directions, though? IIRC the x86 stack extends backwards, so when it needs to allocate a new stack page, it will be at a lower address than the existing stack... whereas this code is counting into the increasing values.
I don't know for sure, but presumably you're correct that the OS will only automatically grow the stack in the correct direction. And you're right about it going downwards. I knew about that fact and almost mentioned it in my previous post, but I didn't make the connection with the direction of the traversal. :-) Oh well; that theory had already been ruled out.

(Though in my defense I was already banking on something going on like the program activating a "automatically map memory" feature of the OS, assuming that's even possible, as otherwise it'd almost certainly have very quickly have hit the stack limit. So in some sense I wasn't really depending on it being the stack operation per se, just something that works similar to it.)

chridd wrote:Could it have corrupted the return address to point to some code that allocates a lot of memory (or perhaps starts other processes in an infinite loop)? Or perhaps corrupted a variable that's passed to malloc at some later point in the program?
That sounds potentially promising, but I'm still at a loss as to what could be going on other than memory exhaustion to make the poorly-behaving program affect other processes so much. Maybe other disk I/O, but... I don't really know how that would happen either, and it'd still be really weird. Any chance of that, Xenomortis?

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Wed Jul 03, 2013 7:53 am UTC

Interesting. I didn't know about that stack extension stuff, but I haven't done any assembly-level programming since the days of the Amiga, which used MC68k chips, and I've never done assembler work on Intel chips. The Amiga OS had little in the way of memory protection, so it was fairly easy for a rogue process to corrupt memory that was being used by other processes.

Chridd's theory of return address corruption sounds good to me. I guess Xenomortis could test that theory by re-running the original code on the original machine, since it's unlikely that the memory configuration will be the same as it was the first time around.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Jul 03, 2013 8:00 am UTC

EvanED wrote:
chridd wrote:Could it have corrupted the return address to point to some code that allocates a lot of memory (or perhaps starts other processes in an infinite loop)? Or perhaps corrupted a variable that's passed to malloc at some later point in the program?
That sounds potentially promising, but I'm still at a loss as to what could be going on other than memory exhaustion to make the poorly-behaving program affect other processes so much. Maybe other disk I/O, but... I don't really know how that would happen either, and it'd still be really weird. Any chance of that, Xenomortis?


From memory, the program looked something like this.

Code: Select all

void separate(char* s, char*d)
{
    while(*d++ = s*++) s*++ = ','; //now I think about it, I don't think t was passed as a parameter at this stage
}

int main()
{
    char s[5] = "test";
    char buffer[10];
    separate(buffer, test);
    printf("%s", buffer);
    return 0;
}

I'll see if I've overwritten my scratch program on this machine.

There was a load of processes running on the machine; several instance of Visual Studio in particular. I think an automated backup process was due to start soon too.


Edit:
That can't be right. The code should (and appears to) hit the null byte at the end of "test".
Changing it to char test[6] = "test1"; corrupts the stack, but the program just terminates with the usual boring error message.
Image

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Jul 03, 2013 8:39 am UTC

I guess I remembered wrong (and made two mistakes in my code).

Code: Select all

void separate(char* s, char*d)
{
    while(*d++ = *s++) ++*s = ',';
}

Causes the behaviour described earlier. This takes care of the "never hitting a null-byte" problem.
I might probe it later, when I'm not supposed to be working.

Edit:
Correction - spoilered because it was added after some discussion.
Spoiler:

Code: Select all

void separate(char* s, char*d)
{
    while(*d++ = *s++) ++*s = ',';
}
Last edited by Xenomortis on Wed Jul 03, 2013 2:03 pm UTC, edited 1 time in total.
Image

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Wed Jul 03, 2013 10:57 am UTC

Xenomortis wrote:++*s = ',';

Argh! My eyes!

:)

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Jul 03, 2013 11:00 am UTC

Yeah, when I tried I thought "there's no possible way I did that". It seems so far detached from what I actually wanted (and I don't think I've ever typed ++x before...).
But, well...
Image

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Wed Jul 03, 2013 11:16 am UTC

I've used ++x from time to time, although I generally prefer to use the postfix form where practical, but ++*x just looks evil. :)

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Jul 03, 2013 11:25 am UTC

PM 2Ring wrote:but ++*x is just evil. :)

FTFY, in light of recent experiences. :wink:
Image

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Wed Jul 03, 2013 12:25 pm UTC

GCC allows binding globals to registers. Now, I'm writing some 8-bit AVR firmware, and I'd like to bind a global uint32_t (4 bytes) to a range of registers (it won't fit in one register, obviously). Does anyone know if that's possible, and if so, how? I could rewrite the parts using that variable in assembly, but that's something I'd really prefer to avoid.

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Wed Jul 03, 2013 12:41 pm UTC

Link wrote:GCC allows binding globals to registers. Now, I'm writing some 8-bit AVR firmware, and I'd like to bind a global uint32_t (4 bytes) to a range of registers (it won't fit in one register, obviously). Does anyone know if that's possible, and if so, how? I could rewrite the parts using that variable in assembly, but that's something I'd really prefer to avoid.

Eeek!

Seriously though, have you tried a union?

User avatar
phlip
Restorer of Worlds
Posts: 7573
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Jul 03, 2013 1:37 pm UTC

Xenomortis wrote:I guess I remembered wrong (and made two mistakes in my code).

Code: Select all

void separate(char* s, char*d)
{
    while(*d++ = *s++) ++*s = ',';
}

Does the compiler really not have a warning for assigning to ++stuff? That's not even allowed in C, but you'd think there'd be a warning for it in C++, certainly for nonvolatile primitive types (where you know there isn't any madness going on in operator++ or operator=)...

Testing it, g++ doesn't have a warning for that, even with -Wall...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Jul 03, 2013 2:02 pm UTC

I am too tired...
I don't know about ++stuff, but it's not really relevant because ++stuff isn't what I was assigning to (I wrote down the code wrong).
The code is *++s, not ++*s. I don't know what ++*s would do. I do not feel like finding out; I've rebooted my machine enough for today.

But yeah, I can do ++i = x without warnings.

For the final time, this is the code that trashes my Windows 7 machine.

Code: Select all

void separate(char* s, char* d)
{
    while(*d++ = *s++) *++s = ',';
}


I don't know how it's possible to make repeated mistakes when transcribing code that revolves around a typo...

Earlier, I tried running the following under the VS debugger.

Code: Select all

void separate(char* s, char* d, int i)
{
    while(*d++ = *s++) *++s = ',';
    i++;
    if(0 == (i%1000)){
        i=i;
    }
}

I set a break point on i=i. It was reached once without issue. When I clicked Continue however...
Image

User avatar
phlip
Restorer of Worlds
Posts: 7573
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Jul 03, 2013 2:14 pm UTC

My only guess is that you're running off the bottom of the stack... so you could be very easily clobbering some information that the OS happens to be storing there. Then you run out of the last (probably only) stack page, get a page fault and an access violation, and something that you've clobbered destroys the Windows exception handler mechanism? Or something? It's really hard to know exactly what's going on at this point.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Wed Jul 03, 2013 4:17 pm UTC

PM 2Ring wrote:
Link wrote:GCC allows binding globals to registers. Now, I'm writing some 8-bit AVR firmware, and I'd like to bind a global uint32_t (4 bytes) to a range of registers (it won't fit in one register, obviously). Does anyone know if that's possible, and if so, how? I could rewrite the parts using that variable in assembly, but that's something I'd really prefer to avoid.

Eeek!

Seriously though, have you tried a union?

I haven't, because I still wouldn't know what the syntax is. The main problem is that having the uint32_t in SRAM generates too many push, pop, lds and sts instructions. I have four spare registers that GCC doesn't use, and if I can bind that uint32_t to them, I believe it would cull 4 pushes, 4 pops, 12 ldses and 12 stses, while adding 4 clrs. That's 104 bytes saved right there, which is a lot on a device with 2K bytes of program memory!

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Jul 03, 2013 5:28 pm UTC

A long shot, but make a static pseudo-`int32` that has `operator=` and `operator int32() const`, no state, and it juggles the `int32` into the `byte`s? Then operate on that `int32`?

Code: Select all

uint8 a,b,c,d; // registers
struct pseudo_uint32 {
  operator uint32() const {
    return a | b<<8 | c<<16 | d<<24;
  }
  pseudo_uint32& operator=( uint32 x ) {
    a = uint8(x);
    x << 8;
    b = uint8(x);
    x << 8;
    c = uint8(x);
    x << 8;
    d = uint8(x);
    return *this;
   }
};
pseudo_uint32 glob_32;

or something like that. Note that glob_32 has no state at all -- a good compiler would even let you take a,b,c,d via reference, realize that they are constant, and optimize their use away. But in your case, no need to put more stress on the poor optimizer.

A fancier "operator T" could also be useful, because C++ does at most one user-defined conversion between any two types. If you create an "operator T" with "is_convertable< uint32, T >" restriction, you can behave more like a "real" uint32 with regards to conversions, and ditto for "operator=".

This could cause code bloat if gcc is unable to delete identical functions (casting to int and uint, say, which may have identical binary implementations).
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Wed Jul 03, 2013 6:48 pm UTC

This is plain C, so that's a bit too fancy!

Since I really only need this for one particular ISR, I could use inline assembly for that. Unless there's an easy way to do this, I guess I'll leave it until I absolutely need the space it saves (though I expect I *will* need every last byte available at some point).

Edit: actually, since I really *do* use that variable only in the ISR, I can move it out of global space and make it static. That saves 32 bytes. :)

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby troyp » Thu Jul 04, 2013 12:11 am UTC

phlip wrote:My only guess is that you're running off the bottom of the stack... so you could be very easily clobbering some information that the OS happens to be storing there. Then you run out of the last (probably only) stack page, get a page fault and an access violation, and something that you've clobbered destroys the Windows exception handler mechanism? Or something? It's really hard to know exactly what's going on at this point.

But if he had a breakpoint after the bad statement and it only fucked up when he continued, that supports the idea that it happened when execution jumped to the overwritten return address, no?

User avatar
sparkyb
Posts: 1091
Joined: Thu Sep 06, 2007 7:30 pm UTC
Location: Camberville proper!
Contact:

Re: Coding: Fleeting Thoughts

Postby sparkyb » Thu Jul 04, 2013 3:12 am UTC

PM 2Ring wrote:I've used ++x from time to time, although I generally prefer to use the postfix form where practical


For some reason x++ seems to be considered standard (at least among new programmers) with ++x being used only occasionally when necessary, but it really should be the other way around. The most common case is in the increment part of a for loop. When you don't care about the return value (don't assign it to anything, use it in a conditional, or dereference it) you should always use ++x. Only use x++ when you actually need to. The reason why is that ++x just increments and then returns itself, but since x++ returns the value *before* the increment, it has to make a copy of x, increment, and then return the copy. For primitive types, like integers used as for loop index variables or pointers into a C array, this makes no difference either way, but it is a good habit to get into so you don't make unnecessary copies when it an STL iterator or some bigger object. The most common valid use of x++ is when copying data from one array to another as in *d++ = *s++; (when there's a code snippet at the end of the sentence, should I close the sentence with a period or semicolon?)

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Thu Jul 04, 2013 4:09 am UTC

sparkyb wrote:...so you don't make unnecessary copies when it an STL iterator or some bigger object.
You advice is good and I advocate the same thing. However, I also feel obligated to point out that optimizers are pretty smart, and in practice even nontrivial types such as std::list iterators (not sure about map) will get optimized.

That said, there's no reason not to do it either, really. And if it's equally readable and equally correct (which prefix ++ is when in the increment part of a for loop or otherwise on its own), why not make the potentially more efficient one automatic?

The most common valid use of x++ is when copying data from one array to another as in *d++ = *s++;
Do I have to turn in my programmer card if loops that do that to copy things make me cringe? I recognize that particular idiom, but otherwise I find I really have to think about order of evaluation when side-effecting expressions are used in a larger expression.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Thu Jul 04, 2013 7:59 am UTC

EvanED wrote:
sparkyb wrote:The most common valid use of x++ is when copying data from one array to another as in *d++ = *s++;
Do I have to turn in my programmer card if loops that do that to copy things make me cringe? I recognize that particular idiom, but otherwise I find I really have to think about order of evaluation when side-effecting expressions are used in a larger expression.

If the program was more than a simple demonstration, I would have taken a more dumb approach.
But then this conversation probably wouldn't have happened.

troyp wrote:But if he had a breakpoint after the bad statement and it only fucked up when he continued, that supports the idea that it happened when execution jumped to the overwritten return address, no?

I cannot tell if it was still inside the loop when it "broke".
Edit:
It never appears to hit any of the instructions outside of the loop (breakpoint set on the instruction the relevant "je x" instruction was pointing to).
I don't even know if that means anything anymore...
Last edited by Xenomortis on Thu Jul 04, 2013 8:09 am UTC, edited 1 time in total.
Image

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Thu Jul 04, 2013 8:08 am UTC

EvanED wrote:Do I have to turn in my programmer card if loops that do that to copy things make me cringe? I recognize that particular idiom, but otherwise I find I really have to think about order of evaluation when side-effecting expressions are used in a larger expression.


No, you are a good person (assuming you don't murder babies as a hobby, although I try not to judge). To me, it comes down to the principle that, unless there is a good reason not to, you should try and make it so your code reads like it's explaining what it is doing. I don't care if there is a slight performance advantage to pointer arithmetic over array syntax, array syntax is easier to read.
Summum ius, summa iniuria.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Coding: Fleeting Thoughts

Postby Jplus » Thu Jul 04, 2013 10:10 am UTC

sparkyb wrote:[...] The most common valid use of x++ is when copying data from one array to another as in *d++ = *s++; (when there's a code snippet at the end of the sentence, should I close the sentence with a period or semicolon?)

Semicolon, obviously;
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Thu Jul 04, 2013 5:22 pm UTC

Syntax trumps grammar: just like you don't capitalize. void, at the start of a sentence, is lower case.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1456
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Thu Jul 04, 2013 5:42 pm UTC

I think you just killed my brain with that last post.
Image

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: Coding: Fleeting Thoughts

Postby troyp » Thu Jul 04, 2013 5:47 pm UTC

You can't omit the semicolon, but the real question is if you omit the period or put it afterwards (with maybe a space or two in between)...

speising
Posts: 2365
Joined: Mon Sep 03, 2012 4:54 pm UTC
Location: wien

Re: Coding: Fleeting Thoughts

Postby speising » Thu Jul 04, 2013 6:07 pm UTC

it's a quotation; obviously, there should be quote marks around it, like "int i = 1;".
that doesn't help you if you follow american punctuation, of course.

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Fri Jul 05, 2013 3:39 am UTC

sparkyb wrote:
PM 2Ring wrote:I've used ++x from time to time, although I generally prefer to use the postfix form where practical


For some reason x++ seems to be considered standard (at least among new programmers) with ++x being used only occasionally when necessary, but it really should be the other way around. The most common case is in the increment part of a for loop. When you don't care about the return value (don't assign it to anything, use it in a conditional, or dereference it) you should always use ++x. Only use x++ when you actually need to. The reason why is that ++x just increments and then returns itself, but since x++ returns the value *before* the increment, it has to make a copy of x, increment, and then return the copy. For primitive types, like integers used as for loop index variables or pointers into a C array, this makes no difference either way, but it is a good habit to get into so you don't make unnecessary copies when it an STL iterator or some bigger object. The most common valid use of x++ is when copying data from one array to another as in *d++ = *s++; (when there's a code snippet at the end of the sentence, should I close the sentence with a period or semicolon?)

Very good points, sparkyb. FWIW, if I'm not actually assigning the value of an increment expression I tend to write it explicitly as x += 1; (except in for statements).


Thesh wrote:
EvanED wrote:Do I have to turn in my programmer card if loops that do that to copy things make me cringe? I recognize that particular idiom, but otherwise I find I really have to think about order of evaluation when side-effecting expressions are used in a larger expression.


No, you are a good person (assuming you don't murder babies as a hobby, although I try not to judge). To me, it comes down to the principle that, unless there is a good reason not to, you should try and make it so your code reads like it's explaining what it is doing. I don't care if there is a slight performance advantage to pointer arithmetic over array syntax, array syntax is easier to read.

Yeah but *d++ = *s++; is a standard idiom, so it shouldn't slow down the reading of any experienced C programmer.


speising wrote:it's a quotation; obviously, there should be quote marks around it, like "int i = 1;".
that doesn't help you if you follow american punctuation, of course.

Or you can put it in bold or italics, like I did above.

User avatar
AlexTheSeal
Posts: 53
Joined: Mon Oct 26, 2009 12:57 am UTC

Re: Coding: Fleeting Thoughts

Postby AlexTheSeal » Fri Jul 05, 2013 5:41 pm UTC

PM 2Ring wrote:The Amiga OS had little in the way of memory protection, so it was fairly easy for a rogue process to corrupt memory that was being used by other processes.


You misspelled "mandatory." Hope this helps.

Seriously, did anyone ever manage to use an Amiga 1000 for more than half an hour without getting a Guru Meditation Error? Jay Miner's design for the original Amiga chipset was fantastic (amazing that he knocked it out of the park twice, first with the Atari 8-bits, then with the Amiga) but the OS was so awful.

Code: Select all

10 REM WORLD'S SMALLEST ADVENTURE GAME
20 PRINT "YOU ARE IN A CAVE (N, S, E, W)? ";
30 INPUT A$
40 GOTO 10

Lulled to sleep by the one-hertz chuckle of Linux logfile writes since 1997.

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Sat Jul 06, 2013 7:06 am UTC

AlexTheSeal wrote:
PM 2Ring wrote:The Amiga OS had little in the way of memory protection, so it was fairly easy for a rogue process to corrupt memory that was being used by other processes.


You misspelled "mandatory." Hope this helps.


It was a great environment to learn to be very careful with pointers in C & assembler because if you got it wrong you'd almost certainly crash the machine. :)

AlexTheSeal wrote:Seriously, did anyone ever manage to use an Amiga 1000 for more than half an hour without getting a Guru Meditation Error? Jay Miner's design for the original Amiga chipset was fantastic (amazing that he knocked it out of the park twice, first with the Atari 8-bits, then with the Amiga) but the OS was so awful.


I had an A1000 and a couple of A2000s (and an A500 someone gave me but which I never used). I still have an A2000 packed up in a box. I admit that the earliest versions of the OS had a few bugs, but later versions were much less fragile, although I did most of my work on an A2000 running on a 68030 with an MMU, so it did have a degree of memory protection.

I was still using & programming the Amiga until the early 2000s, but I must admit that much of my Amiga programming knowledge is now rather hazy.

I thought the OS design was mostly pretty good, considering the space limitations they had to work with. I quite liked the original exec and graphics libraries, although the intuition (user interface) library had some questionable features. Unfortunately, the clean design of graphics & intuition got a bit messy with the later expansions and improvements. However, I will agree that the Amiga DOS library was horrible, but it wasn't actually developed by the Amiga team. Fortunately, it was later re-written in C (it was originally written in BCPL, which explains some of its awfulness), but that didn't really improve matters much.

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Mon Jul 08, 2013 8:51 am UTC

I've managed to get my firmware binary down to 2155 bytes (it was previously 3574 bytes!). 155 bytes to go before it'll fit.

Fun fact: I've had to reinvent multiplication to get it this small. I need to multiply a uint32_t by 10 at some point, and rather than use the vast standard uint32_t multiplication code, I went for this instead:

Code: Select all

__inline__ void mul10slow (uint32_t *x)
{
   uint32_t y;
   *x <<= 1;
   y = *x;
   *x <<= 2;
   *x += y;
}

Since I've had to slightly modify my code to be able to use this, it'll probably be quite a bit slower than the previous approach, but it's not in a critical section, and if the execution time is less than 50 ms or so (~200000 clock cycles with the crystal frequency I'm using), the user won't even notice it.

As for the remaining 155 bytes, if I can find or invent a space-optimised uint32_t divmod10 routine, I'm probably done. ;)

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Mon Jul 08, 2013 11:13 am UTC

Link wrote:As for the remaining 155 bytes, if I can find or invent a space-optimised uint32_t divmod10 routine, I'm probably done. ;)

Well, there's some pretty slick divide by 10 code in this thread, courtesy of jareds, although it's for uint16.

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Mon Jul 08, 2013 12:10 pm UTC

PM 2Ring wrote:
Link wrote:As for the remaining 155 107 bytes, if I can find or invent a space-optimised uint32_t divmod10 routine, I'm probably done. ;)

Well, there's some pretty slick divide by 10 code in this thread, courtesy of jareds, although it's for uint16.

I might be able to turn that into something I can use (my brain doesn't quite work at this moment, so maybe later!), but I also need the modulo 10. Essentially, what I'm trying to implement is this:

Code: Select all

__inline__ uint8_t divmod10 (uint32_t *x)
{
   uint8_t y = *x % 10;
   *x /= 10;
   return y;
}

That causes the generic routine __udivmodsi4 to be pulled in, though, and I was hoping to replace it with something shorter.

I've already cut the binary down to 2116 bytes, so it's only 6% 3.5% too large now. Almost there!
Last edited by Link on Mon Jul 08, 2013 12:38 pm UTC, edited 1 time in total.

User avatar
sparkyb
Posts: 1091
Joined: Thu Sep 06, 2007 7:30 pm UTC
Location: Camberville proper!
Contact:

Re: Coding: Fleeting Thoughts

Postby sparkyb » Mon Jul 08, 2013 12:12 pm UTC

Link wrote:I've managed to get my firmware binary down to 2155 bytes (it was previously 3574 bytes!). 155 bytes to go before it'll fit.


You have to get it down to 2000 bytes, not 2048? I have no idea what this is a firmware for, but a non power of two limit seems odd.

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Mon Jul 08, 2013 12:36 pm UTC

sparkyb wrote:
Link wrote:I've managed to get my firmware binary down to 2155 bytes (it was previously 3574 bytes!). 155 bytes to go before it'll fit.


You have to get it down to 2000 bytes, not 2048? I have no idea what this is a firmware for, but a non power of two limit seems odd.

Ahh, you're right. See, that's what I mean when I say my head isn't working properly! :D


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 10 guests