Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Dicky B
Mar 23, 2004

qntm posted:

Outstanding.
Most languages implements arrays this way, even if you don't realise it. When you call a built in "length" method you are usually referencing an internal counter that exists even if you never need it.

Adbot
ADBOT LOVES YOU

pseudorandom name
May 6, 2007

argv[argc] is guaranteed to be NULL, so technically there's two ways to find out where argv ends. :eng101:

qntm
Jun 17, 2009

Dicky B posted:

Most languages implements arrays this way, even if you don't realise it. When you call a built in "length" method you are usually referencing an internal counter that exists even if you never need it.

Sure, I can't think of any other way to do it. Point being, these languages actually do implement an internal counter of some kind. Unlike C. It's frighteningly low level.

TasteMyHouse
Dec 21, 2006

qntm posted:

Sure, I can't think of any other way to do it. Point being, these languages actually do implement an internal counter of some kind. Unlike C. It's frighteningly low level.

yeah. its C. That's the point.

pseudorandom name
May 6, 2007

You have to keep in mind that C is at its very heart a portable assembler, despite some of the idiotic modern additions to the language.

aux
Oct 25, 2010
If you're using malloc in c to make arrays, its probably easier to just make a macro that uses malloc then creates the array one size bigger and puts the size in the last element (if you really really need to know the size).

Somehow the free function knows how much memory was allocated but its not accesible in C for some reason.

nielsm
Jun 1, 2009



aux posted:

If you're using malloc in c to make arrays, its probably easier to just make a macro that uses malloc then creates the array one size bigger and puts the size in the last element (if you really really need to know the size).

I don't think that would work too well. :)
With that scheme, you need to know the index of the last element to get the length, but the length is what defines the last index.

Better allocate too much, skip the first element, cast it to a size_t and store the number of elements there. Then pass around a pointer to the second element in the allocation. (Remember, that pointer would be invalid to free()!) Define a macro to get the length of an array then, like #define ARRAYLEN(arr) (*(size_t*)((arr)-1)).
Of course this depends on the element size being at least sizeof(size_t).

I believe Delphi uses a scheme like that for longstrings, except also with a reference count (for copy-on-write) added too.

nielsm fucked around with this message at 02:25 on May 30, 2011

mr_jim
Oct 30, 2006

OUT OF THE DARK

aux posted:

Somehow the free function knows how much memory was allocated but its not accesible in C for some reason.

One way to implement malloc/free involves placing a fixed-length "tag" right before the allocated memory that specifies the size of the block, but there's nothing in the standard that requires that.

Making the size accessible to the user would put constraints on how malloc could be implemented, or would at least complicate some implementations. For instance, some allocators will only allocate blocks of memory that are a multiple of some size, and so might allocate more memory than is requested. Which size should be reported, the requested size, or the allocated size? The allocated size probably isn't what the user is interested in, but in order to report the requested size, it needs to be kept track of separately. That increases the space overhead, which could be a problem on smaller systems.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Not a question, just a gripe - loving templates and their incredibly unhelpful error messages. An error on a std::vector's push_back(MyClass(init_data)) call turned out to be an object within MyClass on whose copy constructor I had accidentally omitted a 'const' on the parameter.

Suffice to say the error message was about 40 lines long and had absolutely nothing to do with the contained object type that was causing the problem. Thanks templates!

DeciusMagnus
Mar 16, 2004

Seven times five
They were livin' creatures
Watch 'em come to life
Right before your eyes

nielsm posted:

Define a macro to get the length of an array then, like #define ARRAYLEN(arr) *(size_t*)((arr)-1)).

I do believe this may violate C's strict aliasing rule.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It's fine unless you also access that memory as a T, where T is the element type of the array. The aliasing rules aren't tied to casts.

Anyway, the right way to do this is to always pass around a pair of a pointer and a length, which has the advantages of (1) not having crazy dependencies on the size of the array elements and (2) letting you painlessly construct (non-copied, non-owning) subarrays.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

qntm posted:

Well as is typical it seems that I have answered my own question as soon as I asked it. It seems that sizeof is a compile-time operator - something I have honestly never heard of until now, even after learning about #define and #ifdef.

code:
void callme(int array[]) {
	printf("%d\n", sizeof(array));
	return;
}
History note: This syntax for declaring a pointer argument is a vestige of NB, Ritchie's "embryonic" predecessor to C. (A worthwhile read)

more like dICK
Feb 15, 2010

This is inevitable.
This is Windows specific, but still C++.

I need to create 4 processes that will run concurrently. Is the only way to do this 4 seperate calls to CreateProcess?

edit: Related the above, if I'm using CreateProcess to launch console applications, how can I get them to launch in a new console? Add a CREATE_NEW_CONSOLE flag :downs:

more like dICK fucked around with this message at 21:15 on May 30, 2011

nielsm
Jun 1, 2009



DIW posted:

This is Windows specific, but still C++.

I need to create 4 processes that will run concurrently. Is the only way to do this 4 seperate calls to CreateProcess?

Yes. I haven't really heard of any OS that explicitly has a mechanism to spawn multiple processes at once.

When you use CreateProcess in a loop be sure to take this into account for the lpCommandLine parameter:

CreateProcess posted:

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

Also see Process Creation Flags, there's a bunch of different ways to deal with console windows.

more like dICK
Feb 15, 2010

This is inevitable.
Working perfectly, thanks!

Computer viking
May 30, 2011
Now with less breakage.

nielsm posted:

I believe Delphi uses a scheme like that for longstrings, except also with a reference count (for copy-on-write) added too.

Apart from the refcount, that's a classic Pascal-style string - which makes sense with Delphi-the-language being a Pascal variant.
On the less sensible side, there's also -fpascal-strings for gcc.

Computer viking fucked around with this message at 22:43 on May 30, 2011

nielsm
Jun 1, 2009



Computer viking posted:

Apart from the refcount, that's a classic Pascal-style string - which makes sense with Delphi-the-language being a Pascal variant.

Derail, but classic Pascal strings have a fixed allocation size and a length marker. The string's compile time type carries the allocated size for the string, while the length byte denotes how much of the string is valid. Delphi's long strings have allocation size and actual length the same.

Computer viking
May 30, 2011
Now with less breakage.

nielsm posted:

Derail, but classic Pascal strings have a fixed allocation size and a length marker. The string's compile time type carries the allocated size for the string, while the length byte denotes how much of the string is valid. Delphi's long strings have allocation size and actual length the same.

Aah, right. I'm not sure if I can honestly say "good to know", but anyway. :)

smarion2
Apr 22, 2010
So I'm going back to school here in August and will be taking some C++ classes. The only programming I've done was a visual basic class in High School and a very basic C++ summer camp as a kid.

I read the OP and skimmed through some of this thread and was wondering where the best source on starting to teach myself some stuff. I don't want to be overwhelmed when I go back to school because I've been out of it for so long. TIA :)

shrughes
Oct 11, 2008

(call/cc call/cc)

smarion2 posted:

C++ stuff

Read Accelerated C++ by Koenig & Moo (and do the exercises).

Innocent Bystander
May 8, 2007
Born in the LOLbarn.
I'm having a hard time bringing this code up to GCC 4.x . It compiled fine in GCC and I'm a C/C++ novice at best.

code:
/*
 * function: readn
 *
 * read()'s n bytes from fd
 * returns # of butes read, or -1 for error
 */
int readn(register int fd, register void *ptr, register int nbytes)
{

  int nleft, nread;

  nleft = nbytes;
  while (nleft > 0) {
      nread = read(fd, ptr, nleft);
      if (nread < 0)
        return nread;
      else if (nread == 0)
        break;

      nleft -= nread;
      (char*)ptr += nread;   ///THIS LINE IS BAD
  }
  return (nbytes - nleft);
} /* readn */
This returns an error at the indicated line and while I know about pointers I am unfamiliar with the (char*) syntax and am not sure on how to use it. Any help would be fantastic.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
That's an l-value cast, which people eventually realized were a terrible idea. Just copy the argument into a char* local and use that instead.

Brecht
Nov 7, 2009

Innocent Bystander posted:

I'm having a hard time bringing this code up to GCC 4.x . It compiled fine in GCC and I'm a C/C++ novice at best.

code:
/*
 * function: readn
 *
 * read()'s n bytes from fd
 * returns # of butes read, or -1 for error
 */
int readn(register int fd, register void *ptr, register int nbytes)
{

  int nleft, nread;

  nleft = nbytes;
  while (nleft > 0) {
      nread = read(fd, ptr, nleft);
      if (nread < 0)
        return nread;
      else if (nread == 0)
        break;

      nleft -= nread;
      (char*)ptr += nread;   ///THIS LINE IS BAD
  }
  return (nbytes - nleft);
} /* readn */
This returns an error at the indicated line and while I know about pointers I am unfamiliar with the (char*) syntax and am not sure on how to use it. Any help would be fantastic.
#1, remove the register keyword, it's almost certainly not doing anything for you except pissing off the compiler. #2, remove the (char *) altogether because pointer arithmetic on a void* is gonna be the same as a char* on pretty much every architecture.

edit: rjmccall actually has the correct advice.

That Turkey Story
Mar 30, 2003

Brecht posted:

pointer arithmetic on a void* is gonna be the same as a char* on pretty much every architecture.

You can't do pointer arithmetic with a void*.

Brecht
Nov 7, 2009

That Turkey Story posted:

You can't do pointer arithmetic with a void*.
code:
$ cat innocent.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
	void *p = malloc(1024);
	printf("%x\n", p);
	p++;
	printf("%x\n", p);
	p += 4;
	printf("%x\n", p);
	return 0;
}
$ make innocent && ./innocent
cc     innocent.c   -o innocent
800000
800001
800005

That Turkey Story
Mar 30, 2003

Compile that on most compilers (all standard-compliant compilers) and you will see something along the lines of this (in particular, the errors):

code:
line 7: warning: argument is incompatible with corresponding format
          string conversion
  	printf("%x\n", p);
  	               ^

line 8: error: expression must be a pointer to a complete object type
  	p++;
  	^

line 9: warning: argument is incompatible with corresponding format
          string conversion
  	printf("%x\n", p);
  	               ^

line 10: error: expression must be a pointer to a complete object
          type
  	p += 4;
  	^

line 11: warning: argument is incompatible with corresponding format
          string conversion
  	printf("%x\n", p);
  	               ^

Mikey-San
Nov 3, 2005

I'm Edith Head!

Brecht posted:

code:
$ cat innocent.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
	void *p = malloc(1024);
	printf("%x\n", p);
	p++;
	printf("%x\n", p);
	p += 4;
	printf("%x\n", p);
	return 0;
}
$ make innocent && ./innocent
cc     innocent.c   -o innocent
800000
800001
800005

I'll defer to rjmccall if he says I'm wrong, but I'm pretty sure the behavior of this is undefined. (Edit: Not undefined. See below.) The compiler doesn't know the actual size of a void pointer, so you can't (reliably) do math on it.

vvv and there you go - listen to him

Mikey-San fucked around with this message at 06:07 on Jun 3, 2011

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It's not undefined or implemented-defined behavior; it's just intentionally ill-formed under the standards. However, GCC lets you do arithmetic on void* as an extension, using the same semantics as arithmetic on char*. So you can rely on that program producing that result under GCC and compilers like Clang which support GCC extensions, but you should be aware that it's neither particularly portable nor a good idea.

Innocent Bystander
May 8, 2007
Born in the LOLbarn.
code:
int readn(register int fd, register void *ptr, register int nbytes)
{

  int nleft, nread;
  char* ptr2;           ///Declared char*
  nleft = nbytes;
  while (nleft > 0) {
      nread = read(fd, ptr2, nleft);
      if (nread < 0)
        return nread;
      else if (nread == 0)
        break;

      nleft -= nread;
      ptr2 += nread;   ///CHANGED THIS LINE TO USE ptr2
  }
  ptr = ptr2;          ///ADDED ASSIGNMENT of ptr2 to ptr
  return (nbytes - nleft);
} /* readn */
Since this is in the middle of 5k+ line ecosystem, I'm having trouble unit testing this. Is this a satisfactory fix? Or am I missing the point entirely.

As I look at the code though, and the rest of the code base, I just wonder why it was implemented like that in the first place? Was there a particular mindset in the early 2000s or something?

Innocent Bystander fucked around with this message at 08:12 on Jun 3, 2011

Brecht
Nov 7, 2009

rjmccall posted:

It's not undefined or implemented-defined behavior; it's just intentionally ill-formed under the standards. However, GCC lets you do arithmetic on void* as an extension, using the same semantics as arithmetic on char*. So you can rely on that program producing that result under GCC and compilers like Clang which support GCC extensions, but you should be aware that it's neither particularly portable nor a good idea.
I knew it wasn't a good idea, but the compiler thing was new to me. I -- have learned something today!

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Innocent Bystander posted:

Since this is in the middle of 5k+ line ecosystem, I'm having trouble unit testing this. Is this a satisfactory fix? Or am I missing the point entirely.

Well, let's take a look at it.

code:
int nleft, nread;
  char* ptr2;           ///Declared char*
  nleft = nbytes;
  while (nleft > 0) {
      nread = read(fd, ptr2, nleft);
What is going to happen on that last line?

Also:

code:
  ptr = ptr2;          ///ADDED ASSIGNMENT of ptr2 to ptr
  return (nbytes - nleft);
What is that assignment-immediately-before-return going to achieve?


Innocent Bystander posted:

As I look at the code though, and the rest of the code base, I just wonder why it was implemented like that in the first place? Was there a particular mindset in the early 2000s or something?

The contract of read is that it reads at least some data, but isn't required to read the entire requested amount. There are good reasons for this (what if you're reading over a slow-rear end network link, but have the first bit cached on your end? What if you're reading from a pipe and there is no more data yet?), but for situations where you know the data is there and you know you're going to want it all, a convenience wrapper like this is very useful.

Jabor fucked around with this message at 08:59 on Jun 3, 2011

Gerblyn
Apr 4, 2007

"TO BATTLE!"
Fun Shoe

Innocent Bystander posted:

Since this is in the middle of 5k+ line ecosystem, I'm having trouble unit testing this. Is this a satisfactory fix? Or am I missing the point entirely.

You're forgetting to assign ptr to ptr2 when you initialize it.

Internet Janitor
May 17, 2008

"That isn't the appropriate trash receptacle."
I'm not a huge C programmer, so I need some advice for graphics libraries-

What is the simplest way to get a 320x240x32 graphics buffer to the screen? Right now I'm considering using OpenGL+GLUT or SDL. Both have good cross-platform support and are well known, but I thought it would be worth seeing if I'm overlooking other good options. For reference, I'm running OSX, so something available on fink or MacPorts is desirable.

nielsm
Jun 1, 2009



If you don't actually need the 3D-ness of OpenGL, go for SDL or Allegro.

Also, if you plan on distributing your program/game to others in binary form, don't link it against libraries from MacPorts, Fink or similar. Build your own dependencies in a private prefix instead.

ChiralCondensate
Nov 13, 2007

what is that man doing to his colour palette?
Grimey Drawer

Internet Janitor posted:

I'm not a huge C programmer, so I need some advice for graphics libraries-

What is the simplest way to get a 320x240x32 graphics buffer to the screen? Right now I'm considering using OpenGL+GLUT or SDL. Both have good cross-platform support and are well known, but I thought it would be worth seeing if I'm overlooking other good options. For reference, I'm running OSX, so something available on fink or MacPorts is desirable.
I was really excited at one time about Open/TinyPTC.

AlMightyBawb
Jun 1, 2009
What's a good book for learning C++ basics? I have a small grasp of it currently but I feel like I've skipped over certain things and that I might be developing bad habits so I want to go over everything fresh with some kind of solid reference. I realise there's a few suggestions in the OP but some testimony would be nice before I go and grab one.

wellwhoopdedooo
Nov 23, 2007

Pound Trooper!

AlMightyBawb posted:

What's a good book for learning C++ basics? I have a small grasp of it currently but I feel like I've skipped over certain things and that I might be developing bad habits so I want to go over everything fresh with some kind of solid reference. I realise there's a few suggestions in the OP but some testimony would be nice before I go and grab one.

I read through The C++ Programming Language by Bjarne Stroustrup. He invented the language, so it's hard to go wrong there.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

wellwhoopdedooo posted:

I read through The C++ Programming Language by Bjarne Stroustrup. He invented the language, so it's hard to go wrong there.
Will that go into standard templates for him? I was resistant to using them for a long time because they weren't any part of what I originally learned, and now I feel like they really should be an inherent part of learning C++. So if it doesn't cover them, something that will would at least be worth reading afterwards.

nielsm
Jun 1, 2009



roomforthetuna posted:

Will that go into standard templates for him? I was resistant to using them for a long time because they weren't any part of what I originally learned, and now I feel like they really should be an inherent part of learning C++. So if it doesn't cover them, something that will would at least be worth reading afterwards.

TC++PL covers the STL right from page one and covers most of the design and rationale behind it.
TC++PL might be a fine choice if you've been programming for several years and are already comfortable in at least 2 or 3 different languages, but I don't think it's good for someone who is starting out. It does make a lot of assumptions.

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice

nielsm posted:

TC++PL covers the STL right from page one and covers most of the design and rationale behind it.
TC++PL might be a fine choice if you've been programming for several years and are already comfortable in at least 2 or 3 different languages, but I don't think it's good for someone who is starting out. It does make a lot of assumptions.

You could make a pretty strong argument that C++ itself isn't a good choice for someone like that if there aren't external motivators.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply