In an effort to stop being such a fucking noob, I’ve seriously taken up C. As a natural transition/crutch, I have started with PHP extensions. The PHP API basically picks your droppings up after you with a plastic bag, so it’s pretty easy. Using ext_skel gave me pretty much everything I needed, since I’ve only written one function so far and have not done anything fancy.
The extension is called “human,” short for “human readable.” The first function, human_interval_precise, simply represents a number of seconds in the largest “precise” time units possible. That is, thousands of seconds are converted to weeks, days, hours, minutes, and seconds as needed. The source is here.
Lessons
I’m obviously still a giant noob, but there are some things that I have picked up along the way (mostly via Crowley) that made things a lot clearer. Hopefully my posting this will help other noobs following in my footsteps.
“Pointers are just numbers”
Yup. Just the number of memory blocks from the start of the segment of memory you’re dealing with. “Pointer math” is really just math: p+5 really is just the position in memory 5 blocks away from the start of p. The size of the blocks is determined by the pointer type, so if you have a char pointer, the blocks are 1 byte.
an array is just a pointer to a set of consecutive memory blocks
The name of the array is just the pointer to the first element. This is particularly important with char arrays. When I do the following in my code, I am just adding output to the end of an already existing “string.”
sprintf(retstr+strlen(retstr), "%dd ", days);The K&R section on the relationship between arrays and pointers is incredibly useful.
Always remember to initialize your strings
Nothing says “FAIL” like running your PHP function more than once in the same script and seeing it return its result appended to the end of the result from the previous call. A simple
*retstr = 0;at the top of the function takes care of the problem. Otherwise, your char pointer ends up pointing to memory that isn’t claimed by anything else, but isn’t cleared either. In the case of consecutive PHP function runs, it just happens to be the previous output. It could end up being any sort of useless garbage.
I started writing this entry a few weeks ago and got sidetracked by a bigger and more interesting project/thanksgiving. As a result, I don’t remember what else I was going to write, so I’ll just wrap it up. More C learnings coming soon. It has been a humbling experience to say the least.
Tags: c php extension
[...] is the original post: Learning to walk after running for 4 years: from PHP to C Related ArticlesBookmarksTags PHP PHP is a computer scripting language. Originally [...]
But why were you ever in a position to reuse a character buffer? Relatedly, using sprintf(), strcpy() or basically anything but strcat() to set the string will avoid absolutely having to do *retstr = 0; to get an empty string.
(god this color scheme is ugly…)
You didn’t pay attention. I wasn’t reusing it. It is declared at the top of every function (you can look at the source, the link is in the post
), but because I wasn’t zeroing it out, PHP would append the result of each time the function was executed to the result of the previous execution.
Since I didn’t know which if block would actually start writing to the return string (weeks, days, etc), I just used sprintf with the pointer to the string+its length as the first argument, so if I didn’t initialize the string explicitly, it would be writing to whatever C/PHP assigned the pointer to. For whatever reason (probably due to PHP’s garbage collection having cleared the memory allocated by the previous time the function was run), C/PHP assigned it to the start of the previous execution’s return value. I guess since those happened to be characters, C was fooled into thinking that there was already something legit at that location. strlen returned the length up until the \0, and so my function ended up appending to the results of the previous time it was run. That’s my guess, but I could be completely wrong.
In any case, adding the *retstr = 0; line fixed the issue.
does doing *retstr=0; do something that a char retstr[60] = “”; wouldn’t do much more elegantly? I mean, I actually think your option might be more efficient as I think mine sets all the characters in it to null, but I’m not sure. If I wanted to really be sure, I’d look into bzero() or memset(). Or I’d say it’s prettier to write retstr[0] = 0; rather than the pointer notation.
I have no idea what I’m talking about, I’m just trying to remember the C that I wrote 3 months ago.
If I understand K&R correctly, C will convert foo[i] into *(foo+i) before evaluating it anyway, so I’m just saving the compiler some work. I’m not sure what =”" does. bzero fills all the spots with 0, which I don’t need, since I just need to null-terminate the string at the 1st char. I think it’s just a matter of taste/what Crowley told me to do