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
teen bear
Feb 19, 2006

I'm building my first linked list in C and I'm running into trouble. Whenever I have a function that returns a pointer to a node to the main file and I try to work with it I get a "dereferencing pointer to incomplete type" error.

Am I doing something wrong with my header files? I've tried changing around where Node is declared but I can't figure it out.

Adbot
ADBOT LOVES YOU

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

This is probably the classic "how to use a datatype in a datatype that you're currently defining" problem. How are you defining your node struct?

teen bear
Feb 19, 2006

Dijkstracula posted:

This is probably the classic "how to use a datatype in a datatype that you're currently defining" problem. How are you defining your node struct?

code:
typedef struct NODE Node;

struct NODE
{
   int count;
   Node *next;
};

MrMoo
Sep 14, 2000

code:
typedef struct Node Node;

struct Node
{
   int count;
   struct Node *next;
};
You cannot use the typedef within the declaration, is there any logic behind this limitation?

MrMoo fucked around with this message at 08:44 on Dec 3, 2009

Mr.Radar
Nov 5, 2005

You guys aren't going to believe this, but that guy is our games teacher.
Change that code to
code:
typedef struct NODE
{
   int count;
   struct NODE *next;
} Node;
and make sure you put it in the header file your main file includes.

teen bear
Feb 19, 2006

Thanks. Is there any reason you can't use the typedef in that situation?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

teen bear posted:

Thanks. Is there any reason you can't use the typedef in that situation?

The error tells you why. It's an incomplete type (until the definition of the struct is finished).

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
fyi typedefs and structure tags have separate namespaces so you don't strictly need to name them differently, cf http://codepad.org/ILEfyF3L

This doesn't mean you should, but you can

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.

Mr.Radar posted:

make sure you put it in the header file your main file includes.
This is the only thing that he did wrong; his original typedef/struct is totally legitimate and doesn't need to be changed.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Mustach posted:

This is the only thing that he did wrong; his original typedef/struct is totally legitimate and doesn't need to be changed.

Hm, yeah, you're right. That's what I get for answering questions about something I never actually use, and without actually consulting the spec (or even a compiler).

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
There are three C language rules interacting here.

1. Identifiers live in different "name spaces". First, every function has its own namespace of labels. Second, every struct or union has its own namespace of member names. Third, there's a global namespace of "tag" names used to identify structs, unions, and enums using the syntax (e.g.) struct NODE. Finally, there's an "ordinary" namespace containing every other use of an identifier, organized by the usual rules of lexical scope.

2. Tag names don't need to be pre-declared. If you write struct foo in the middle of some arbitrary code, and the C compiler hasn't already seen a type with that name in the tag namespace, then the compiler will implicitly declare an incomplete struct type named foo in the tag namespace, and as long as you don't actually need the definition of that struct type right now, everything is great. This is why you can write typedef struct NODE Node even before you've defined struct NODE: you're implicitly declaring a type named NODE, and the typedef doesn't care that the type is still incomplete.

3. Typedefs live in the ordinary namespace. This means that if you have a typedef named "foo", you can't have (e.g.) a variable in the same scope named "foo". It also means that typedef names are in a different namespace from tag names. This means it's legal to write typedef struct foo foo;, and it just means that, in this lexical scope, the ordinary name foo can be used to refer to the struct type named foo. It also means that there's not necessarily any relationship between a typedef named foo and a tag type named foo.

So when you wrote struct Node* next;, the struct Node part actually (by rule 2) implicitly declared an incomplete struct type named Node, which (by rule 3) has no relation to the typedef named Node, and (most importantly) is completely distinct from struct NODE.

EDIT: wait, there was some crazy edit going on here.

rjmccall fucked around with this message at 07:00 on Dec 3, 2009

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

rjmccall posted:

So when you wrote struct Node* next;, the struct Node part actually (by rule 2) implicitly declared an incomplete struct type named Node, which (by rule 3) has no relation to the typedef named Node, and (most importantly) is completely distinct from struct NODE.

He didn't write that, though. Also, your explanation in (3) is inaccurate if by "the same scope" you are including inner scopes: http://codepad.org/ztM03RqI

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Avenging Dentist posted:

He didn't write that, though. Also, your explanation in (3) is inaccurate if by "the same scope" you are including inner scopes: http://codepad.org/ztM03RqI

He did, but then he changed it in an edit.

Also, no, I am not including inner scopes, because inner scopes in C allow arbitrary ordinary names from outer scopes to be shadowed. Compare

code:
void foo() {
  int a = 0;
  {
    int a = 1;
  }
}

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

rjmccall posted:

Also, no, I am not including inner scopes, because inner scopes in C allow arbitrary ordinary names from outer scopes to be shadowed.

I'm sure you know that, but for the purposes of edification, I figured people should be aware of some of the weirdness that the symbol table in C is capable of.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Avenging Dentist posted:

I'm sure you know that, but for the purposes of edification, I figured people should be aware of some of the weirdness that the symbol table in C is capable of.

That is a good point. Behold the weirdness of C.

Optimus Prime Ribs
Jul 25, 2007

C++ Question.

How bad of an idea is it to use this code:
code:
bool exists(std::vector<int> vec, int key)
{
	try
	{
		vec.at(key);
	}
	catch(std::exception &e)
	{
		return false;
	}

	return true;
}
I can't think of anything bad that could cause, though I'm still pretty new to try/catch.

That Turkey Story
Mar 30, 2003

Optimus Prime Ribs posted:

C++ Question.

How bad of an idea is it to use this code:
code:
bool exists(std::vector<int> vec, int key)
{
	try
	{
		vec.at(key);
	}
	catch(std::exception &e)
	{
		return false;
	}

	return true;
}
I can't think of anything bad that could cause, though I'm still pretty new to try/catch.

That would work, but you shouldn't use exceptions for basic control flow. Just check against the size. Also, don't pass the vector around by value like that.

code:
bool exists(std::vector<int> const& vec, std::vector<int>::size_type key)
{
  return key < vec.size();
}

Optimus Prime Ribs
Jul 25, 2007

Well that's a hell of a lot more simple.
Thanks.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Good news, everyone: clang is now capable of fully parsing its own source code. There is, I'm sure, a lot of work to be done for codegen, but it's a pretty big step towards being self-hosting.

That Turkey Story
Mar 30, 2003

Avenging Dentist posted:

Good news, everyone: clang is now capable of fully parsing its own source code. There is, I'm sure, a lot of work to be done for codegen, but it's a pretty big step towards being self-hosting.

Awesome.

DoctorTristan
Mar 11, 2006

I would look up into your lifeless eyes and wave, like this. Can you and your associates arrange that for me, Mr. Morden?
Is type size_t always an alias for an unsigned integral type? So depending on the implementation it could be either an unsigned int or an unsigned long?

Nigglypuff
Nov 9, 2006


BUY ME BONESTORM
OR
GO TO HELL

Avenging Dentist posted:

Good news, everyone: clang is now capable of fully parsing its own source code. There is, I'm sure, a lot of work to be done for codegen, but it's a pretty big step towards being self-hosting.
Epic clang win! ftw... :bubblewoop:

covener
Jan 10, 2004

You know, for kids!

DoctorTristan posted:

Is type size_t always an alias for an unsigned integral type? So depending on the implementation it could be either an unsigned int or an unsigned long?

ANSI C says yes. SUS adds ssize_t as the signed counterpart.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

DoctorTristan posted:

Is type size_t always an alias for an unsigned integral type? So depending on the implementation it could be either an unsigned int or an unsigned long?

Or even unsigned long long, as on LLP64 platforms like Win64. But yes, it's always an alias for an unsigned integral type.

The Red Baron
Jan 10, 2005

Question to the SFINAE experts. I'm trying to debug some code which works on both MSVC and GCC, but fails on ICC. Here's a watered down example which captures the essence of it:
code:
class a_fancy_class
{
  // For all arity overloads, BaseAbstract is a type from which an internal
  // argument set is fetched. argtype_lookup for any given AbstractType
  // is only valid for a certain arity and will fail otherwise. The function
  // should always be called with the correct arity and with an explicit
  // template type, e.g. fancy.dostuff<mytype>("hello world") where mytype
  // maps to a 1-ary argument set
  // Problem: ICC chokes at this, attempting to instantiate all overloads
  // Question: is this not a valid form of SFINAE?
  template <typename BaseAbstract>
  void dostuff(typename argtype_lookup<BaseAbstract, 0>::type arg0) const
  {
  }

  template <typename BaseAbstract>
  void dostuff(
      typename argtype_lookup<BaseAbstract, 0>::type arg0
    , typename argtype_lookup<BaseAbstract, 1>::type arg1) const
  {
  }

  template <typename BaseAbstract>
  void dostuff(
      typename argtype_lookup<BaseAbstract, 0>::type arg0
    , typename argtype_lookup<BaseAbstract, 1>::type arg1
    , typename argtype_lookup<BaseAbstract, 2>::type arg2) const
  {
  }

  // ...
};
All function arguments are dependent on a template arg, so why does ICC 1) attempt to instantiate overloads with a mismatching arity and 2) whine when the overload fails? It seems to me this should work correctly.

That Turkey Story
Mar 30, 2003

The Red Baron posted:

All function arguments are dependent on a template arg, so why does ICC 1) attempt to instantiate overloads with a mismatching arity and 2) whine when the overload fails? It seems to me this should work correctly.

Looks fine to me, I'm pretty sure that's a compiler bug.

That Turkey Story
Mar 30, 2003

Just for a sanity check, you're sure argtype_lookup<BaseAbstract, 2>::type is not defined when BaseAbstract represents something of arity 1? Maybe you have a default template definition that defines it to void or something by accident?

The Red Baron
Jan 10, 2005

That Turkey Story posted:

Just for a sanity check, you're sure argtype_lookup<BaseAbstract, 2>::type is not defined when BaseAbstract represents something of arity 1? Maybe you have a default template definition that defines it to void or something by accident?
It's defined as
code:
  template <typename Abstract, std::size_t N>
  struct argtype_lookup
  {
    typedef BOOST_DEDUCED_TYPENAME mpl::at<
        BOOST_DEDUCED_TYPENAME abstract_factory_field<
          BOOST_DEDUCED_TYPENAME mpl::at<type_map_type, Abstract>::type
        >::func_type
      , mpl::int_<N + 1> // +1 since the first element is the result type
    >::type type;
  };
where type_map_type is an internal MPL mapping of Abstract -> Abstract* (arg0, ..., argn). If it's valid, it's because of implementational details of mpl::at, which is plausible. I'll try to do the instantiation indirectly via a template bool-specialized on N being less than the arity of the mapped type. That should at least make sure type isn't present if N is out of bounds

That Turkey Story
Mar 30, 2003

The Red Baron posted:

It's defined as

That's the problem right there. Regardless of whether or not that operation used in the definition of type is valid does not matter. SFINAE is substitution failure is not an error. If argtype_lookup's definition has an error when being instantiated that would still cause an error, which is correct compiler behavior.

The Red Baron
Jan 10, 2005

That Turkey Story posted:

That's the problem right there. Regardless of whether or not that operation used in the definition of type is valid does not matter. SFINAE is substitution failure is not an error. If argtype_lookup's definition has an error when being instantiated that would still cause an error, which is correct compiler behavior.

This shouldn't be an issue if the compiler didn't attempt to instantiate overloads with other arities than that which is actually being called, since argtype_lookup should never fail for the correct type and arity. I'm honestly very puzzled as to why it does that. Any ideas?

That Turkey Story
Mar 30, 2003

The Red Baron posted:

This shouldn't be an issue if the compiler didn't attempt to instantiate overloads with other arities than that which is actually being called, since argtype_lookup should never fail for the correct type and arity. I'm honestly very puzzled as to why it does that. Any ideas?

The expression fancy.dostuff<mytype> is the part that causes substitution of mytype into the function template signatures, which is what determines the set of candidates. Only after that happens does overload resolution occur. The fact that you are passing a certain number of arguments does not affect this since that is handled after substitution takes place.

The Red Baron
Jan 10, 2005

That Turkey Story posted:

The expression fancy.dostuff<mytype> is the part that causes substitution of mytype into the function template signatures, which is what determines the set of candidates. Only after that happens does overload resolution occur. The fact that you are passing a certain number of arguments does not affect this since that is handled after substitution takes place.

That explains everything, and I truly wish I had properly understood that aspect of SFINAE sooner. I replaced the lookup with this
code:
  template <typename Abstract, std::size_t N, bool Enable>
  struct argtype_lookup_impl {};

  template <typename Abstract, std::size_t N>
  struct argtype_lookup_impl<Abstract, N, true>
  {
    typedef BOOST_DEDUCED_TYPENAME mpl::at<
        BOOST_DEDUCED_TYPENAME abstract_factory_field<
          BOOST_DEDUCED_TYPENAME mpl::at<type_map_type, Abstract>::type
        >::func_type
      , mpl::int_<N + 1> // +1 since the first element is the result type
    >::type type;
  };

  template <typename Abstract, std::size_t N>
  struct argtype_lookup
    : argtype_lookup_impl<
          Abstract
        , N
        , ((boost::function_types::function_arity<
            BOOST_DEDUCED_TYPENAME mpl::at<type_map_type, Abstract>::type
          >::value) >= N)
      >
  {};
and it seems to do the job with properly slicing off the overload resolution set, since there aren't any instantiation errors any more. Now I'm left wondering why no version I've tested of MSVC or GCC have caught that issue at all

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

The Red Baron posted:

Now I'm left wondering why no version I've tested of MSVC or GCC have caught that issue at all

Because the template implementations in MSVC and GCC are, respectively, terrible and mediocre. Chances are if ICC is giving you an error, you have a bug, since ICC uses EDG as a frontend (notable for being the only frontend that supports export template*).

* But ICC disables this for good reason (it sucks)

That Turkey Story
Mar 30, 2003

Avenging Dentist posted:

Because the template implementations in MSVC and GCC are, respectively, terrible and mediocre. Chances are if ICC is giving you an error, you have a bug, since ICC uses Comeau as a frontend (notable for being the only frontend that supports export template*).

* But ICC disables this for good reason (it sucks)

Well, ICC and Comeau both use the EDG front end. ICC does have some compliance issues that Comeau does not have.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

That Turkey Story posted:

Well, ICC an Comeau both use the EDG front end. ICC does have some compliance issues that Comeau does not have.

Yeah, see my ninja edit. I got mixed up when I was typing it out.

Sab669
Sep 24, 2009

I can't seem to find a C# thread, so forgive me if this is the wrong place.

I have to make a very basic calculator (input a number, operator, and a number) for class that only accepts numbers between 0 and 1,000,000 and rounds the result to 4 decimal places.

http://pastebin.com/m6fb0ee39

I know my code is probably in piss-poor format, I don't know much about coding folkways- my school teaches code first, then proper structure on how to make applications during the Bachelor's degree.

Anyways, everything works good and proper except for the Math.Round(results, 4); in any of my functions. I can't seem to see what I'm doing wrong :psyduck:

litghost
May 26, 2004
Builder

Sab669 posted:

I can't seem to find a C# thread, so forgive me if this is the wrong place.

I have to make a very basic calculator (input a number, operator, and a number) for class that only accepts numbers between 0 and 1,000,000 and rounds the result to 4 decimal places.

http://pastebin.com/m6fb0ee39

I know my code is probably in piss-poor format, I don't know much about coding folkways- my school teaches code first, then proper structure on how to make applications during the Bachelor's degree.

Anyways, everything works good and proper except for the Math.Round(results, 4); in any of my functions. I can't seem to see what I'm doing wrong :psyduck:

Read the documentation and look at the examples.

csammis
Aug 26, 2003

Mental Institution

And then hit up the C# thread.

Sab669
Sep 24, 2009


I did! I copy-pasted the C# example right from the example and then changed it so that it had my variable in place. That was the first link in google.


Thanks, I'll direct any future questions there instead.

Adbot
ADBOT LOVES YOU

RichardA
Sep 1, 2006
.
Dinosaur Gum

Sab669 posted:

I did! I copy-pasted the C# example right from the example and then changed it so that it had my variable in place. That was the first link in google.
Parameters
d Type: System.Decimal
A decimal number to be rounded.
decimals Type: System.Int32
The number of decimal places in the return value.

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