11 ms·
How Do I Declare a Function Pointer in C?
- cestith 10y agoFor anyone unable or unwilling to access that domain name for work purposes or filtering purposes, the linked page lists this alternative: http://goshdarnfunctionpointers.com/ http://goshdarnfunctionpointers.com/
- jerryr 10y agoThanks! Unfortunately, the page currently uses Hover's "stealth redirect" which embeds the profane URL in an iframe. So, if the profane URL is actually blocked by content filtering, you probably still won't be able to access it. I'm actively working on the page. Once it stabilizes, I'll consider mirroring a sanitized version instead of using the "stealth redirect".
- mmphosis 10y agoUnable to access this site due to the profanity in the URL? http://goshdarnfunctionpointers.com http://goshdarnfunctionpointers.com is a more work-friendly mirror. which states: Unable to access this site due to the profanity in the URL? http://goshdarnfunctionpointers.com http://goshdarnfunctionpointers.com is a more work-friendly mirror. which is a possibly an offending link to itself. But, there is also possibly the more benignly named: http://functionpointers.com/ http://functionpointers.com/
- mediocrejoker 10y agoEven the last one is blocked for me. Luckily there is only one IT guy for the entire company and he will generally whitelist anything you ask for.
- a3n 10y agoNot to infringe on your free speech, but you could save yourself some time and do your potential readers a favor if you just fucking didn't swear in your domain name. :)
- rand77763 10y agoWait, what type of fucked up world do people exist in where a website is blocked due to the word "fuck".
- wott 10y agoWhy did you post an empty comment?
- flukus 10y agoShitty corporate ones. I used to work at a place that filtered the content too, so this page would be blocked by your post.
- xienze 10y agoYou don't think perhaps a filter might assume that a website whose URL contains "fuck" might have something to do with porn?
- deleted 10y ago[deleted]
- deleted 10y ago[deleted]
- theophrastus 10y agoOr if one doesn't have cdecl installed there's an online version[1] which has proven as a useful check on several occasions [1] http://cdecl.org/ http://cdecl.org/
- TorKlingberg 10y agocdecl is nice and all, but it will fail if there is any type that isn't a simple built-in C type. It's rare that I can just copy-paste a declaration into cdecl.
- dnquark 10y agoThe trick to reading crazy C declarations is learning the "spiral rule": http://c-faq.com/decl/spiral.anderson.html http://c-faq.com/decl/spiral.anderson.html (here are more examples, with nicer formatting: http://www.unixwiz.net/techtips/reading-cdecl.html http://www.unixwiz.net/techtips/reading-cdecl.html)
- paulnechifor 10y agoThe "spiral rule" doesn't work all the time. See this previous HN comment by stephencanon: https://news.ycombinator.com/item?id=12775862 https://news.ycombinator.com/item?id=12775862 . Also this comment by Linus Torvalds (copy pasted because I don't know how to link to Google+ comments): > I don't think that works. It breaks trivially for consecutive [] or * cases, something that he carefully didn't have in his examples. > So the examples were made up to make it look like it's a spiral, but type parsing is about precedence, not about spirals. It so happens that the higher-precedence operators ([] and ()) are on the right-hand side, which is why it "works" to start on the right. > And it doesn't explain why > typedef int (fn_t[][2])(void); > is ok, but > typedef int (fn_t[2][])(void); > is not. > "Spirals"? I don't think so.
- dnquark 10y agoAll these years I assumed that the 'spiral rule' and 'right-left rule' (linked from the stephencanon comment above, and also described in my second link) are two ways to describe the same algorithm, but, reading closely, they aren't! I guess 'spiral rule' is a stickier name, which is why it's something that people remember even though it's janky.
- a_t48 10y agotypedef int *(**fn_t[][2])(void); is ok, but typedef int *(**fn_t[2][])(void); is not. (fixed formatting?)
- colanderman 10y agoNo, the trick is to remember that declaration follows use. Declare a symbol using (nearly) the same exact syntax you would use to extract a value of the base type from that symbol. See also my comment last time this subject came up: https://news.ycombinator.com/item?id=12775966 https://news.ycombinator.com/item?id=12775966
- bstamour 10y agoThis is one of those cases where I prefer C++ template <typename Func> using function_ptr = add_pointer_t<Func>; and now declarations are a bit more sane: void foo(function_ptr<void (int)> callback);
- david-given 10y agoIn C, the easiest thing to do is to just use a typedef. You get to use the same syntax as for normal function calls with no trying to remember where that blasted extra * goes, and typically end up with cleaner code anyway. typedef void function_ptr_t(int i); function_ptr_t* ptr;
- bstamour 10y agoYeah, typedefs solve the problem for fixed types. I guess you could use a macro to create a generic FUNC_PTR or something as well.
- ramshorns 10y agoMacros are often a bad idea for defining types. If you do #define INT_PTR int* INT_PTR p, q; the code is actively misleading. Is there a better way to do it for function pointers?
- flukus 10y agoThere are a few other problems with multiple declarations aren't there? I though they were discouraged in c.
- Const-me 10y agoIn C++, pointers to member functions are even more cumbersome than C function pointers.
- bstamour 10y agoAgreed. I rarely use pmf's, so every time I do I have to look up the syntax again.
- TheAdamist 10y agoThe new c++ alt function syntax talked about here: https://blog.petrzemek.net/2017/01/17/pros-and-cons-of-alternative-function-syntax-in-cpp/ https://blog.petrzemek.net/2017/01/17/pros-and-cons-of-alter... mentions replacing function declarations for void (*get_func_on(int i))(int); with auto get_func_on(int i) -> void (*)(int); which looks a lot more readable to me.
- Longhanks 10y agoI'd say this is even more readable: auto get_func_on() -> std::function<void(int)>
- _lm_ 10y agoIt's more readable, but using std::function here introduces a second layer of indirection vs using a plain function pointer. More specifically, std::function's operator() is virtual, and calls into a subclass that's specialized to function pointers of type void(int). The subclass then performs the actual function pointer call.
- gpderetta 10y agoTechnically function::operator() is not virtual (which wouldn't be very useful as std::function has value semantics), but it does runtime dispatching internally using an unspecified mechanism. This can be virtual functions, or, more commonly, an hand rolled vtable. In the last case, if std::function is constructed with a function pointer exactly matching its signature it could in principle avoid the thunk and directly point to the function itself. I don't think most implementations bother. /pedantic
- petters 10y agoJust use the typedef. Even if you personally find the other variants readable, chances are that your peer reading your code doesn't.
- 2trill2spill 10y agoNo don't use typedefs there's no real reason[1] and it may cause problems. Also if your peer can't read a function pointer I don't know what help you plan on getting from them anyway, chances are you are helping/teaching them, not the other way around. [1]: http://yarchive.net/comp/linux/typedefs.html http://yarchive.net/comp/linux/typedefs.html
- moron4hire 10y agoJust because Linus Torvalds is a successful programmer doesn't mean he is at all correct about issues of programming. The vast majority of any of the opinions I've seen him express on programming fly in the face of good engineering practice under some guise of "real, macho programmers don't need tools". I'm not afraid to admit: I need tools. I need lots and lots of tools to do my job. The more the computer can be used to make my job easier, the better. There is no virtue in hard work for hard work's sake.
- 2trill2spill 10y ago> Just because Linus Torvalds is a successful programmer doesn't mean he is at all correct about issues of programming. The vast majority of any of the opinions I've seen him express on programming fly in the face of good engineering practice under some guise of "real, macho programmers don't need tools". Is he wrong in this instance or our you going to ignore his point because he's not always right? > I'm not afraid to admit: I need tools. I need lots and lots of tools to do my job. The more the computer can be used to make my job easier, the better. There is no virtue in hard work for hard work's sake. So, as a C programmer I use lot's and lot's of tools. But that doesn't change the point that many view typedefs as bad practice[1]. [1]: http://stackoverflow.com/questions/3781932/is-typedefing-a-pointer-type-considered-bad-practice http://stackoverflow.com/questions/3781932/is-typedefing-a-p...
- favorited 10y agoSee related: http://fuckingblocksyntax.com http://fuckingblocksyntax.com http://fuckingclangwarnings.com http://fuckingclangwarnings.com
- deleted 10y ago[deleted]
- hzhou321 10y agoI never got used to having variables sandwiched inside a type. I know I am not supposed to suggest out-of-the-box, but why can't we add a new syntax, e.g.: return_type Fn(parameters) var; typedef return_type Fn(parameters) TypeName; where Fn is a new keyword -- or not, if compiler understands dummy syntax -- (I would suggest λ when using greek letters in code become norm). It simplifies the C syntax a lot IMHO. PS: now I am out-of-the-box, maybe this is better: Fn{return_type, param1, param2} *var;
- eridius 10y agoYou'd have to call it something like `_Fn` instead, or you're going to conflict with existing code (the C standard reserves identifiers starting with an underscore followed by a capital letter; it also reserves identifiers starting with two underscores, but it's fairly common for code to ignore that and use identifiers like that anyway).
- pwdisswordfish 10y agoIIRC the former is basically what D does. The keyword is `function`.
- hzhou321 10y agoAnother thorn in the C syntax is to allow a single statement following if, for, while, etc.. How many pitfalls, walk-around have we struggled with because of it? Just put the braces into the statement syntax please.
- kruhft 10y agoOne of the only reasons I had "The C Programming Language" on my desk when I was a C coder. The only thing I could never remember...
- porjo 10y agonoscript shows a nasty looking XSS warning when I click any of the 'example code' links.
- int_19h 10y agoEvery time I have to deal with the declarator syntax in C or C++, I can't help but ponder what K&R were thinking when they designed this. It's not like there weren't other languages back then with a saner approach. It looks like what they did was take the syntax from B: auto x[10]; and generalize it such that the type name ended up before the variable name, as in Algol. But in B this worked much better, because it didn't have array types (or pointer types, or function types) - everything was a machine word. So [] in a variable declaration was just to allocate memory to which the variable would refer; the variable itself would still be a word. When they made [] part of the type, and added pointers and function types, the result was a mess.
- clishem 10y agoWhat if I told you that even declarations like char const *(* const (*(*ip)())[])[] are trivial to read? [Read this](http://www.icce.rug.nl/documents/cplusplus/cplusplus03.html#an116 http://www.icce.rug.nl/documents/cplusplus/cplusplus03.html#...) and you'll never struggle with any declaration ever again.
- Rangi42 10y ago"Unambiguous" is not the same as "trivial". C code generally reads left to right, so a trivial syntax for declaring, say, an array of const pointers to functions that take a const pointer to a char and return a const pointer to a char, would have tokens for those things in that order.
- userbinator 10y agoC code generally reads left to right No it doesn't: p += k[foo(bar, baz, 3*(quux+1))] << 32-m[++i];
- int_19h 10y agoI know the rules, and how to apply them. But they are not trivial. The fact that such documents need to be written in the first place, and the fact that utilities like cdecl exist, is a strong testimony to that.
- shmerl 10y agoThe syntax is atrocious, but there isn't much C can do about it.
- userbinator 10y agoThe easiest and best way to learn the syntax is to not memorise specific cases but the grammar itself, which IMHO is no more difficult than the existing concept of operator precedence. Everyone using C should hopefully already know that multiplication has higher precedence than addition, so likewise function call (and array subscripting) has higher precedence than pointer dereference. Thus this table should make it clear that combining the two operators creates pointer-to-function: T x; T *y; T f(); T (*g)(); T pointer to T function returning T pointer to function returning T and the alternative, T h(); , is parsed as T (h()); and thus becomes "function returning pointer to T". The apparent struggle I see with this syntax has always somewhat puzzled me, because I don't see the same level of complaints about e.g. arithmetic expressions (like 6+3*4/(2+1)) which are parsed with precedence in much the same way. K&R even has a section on writing a parser that recognises this syntax, so I suspect it's really not that hard, but the perception spread by those who didn't learn the syntax but only memorised the "easy cases" is making it appear more difficult than it really is.
- tronje 10y agoNice explanation, thanks; your formatting got a little messy right after the code block, though, because things between asterisks are rendered cursive.
- bnmfsd 10y agoStackoverflow related question/answer: http://stackoverflow.com/a/34548829/1119701 http://stackoverflow.com/a/34548829/1119701
- hzhou321 10y agoWhat we need realize is that simple grammar does not always lead to simple comprehension. Nesting the grammar elements more than a few levels is always difficult for our current biology equipment.
- nialv7 10y agoYou define a variable the same way you would use it. int *a -> expression *a has type int. int *a[10] -> *a[_] has type int. int (*a)[10] -> (*a)[_] has type int. int (*a)(int, int) -> (*a)(_, _) has type int. No need for complicated things like "spiral rules", etc.
- cmrdporcupine 10y agoNeeds more profanity. The whole syntax is profane.