Liste des Groupes | Revenir à cl c |
On 01/12/2024 15:50, David Brown wrote:Okay, I understand your point now. And I can see there is a certain similarity between between maintaining the extern function declarations in a header, and maintaining a list of static function declarations in the C file. (I refer to "extern function declarations" to distinguish them from static declarations - and because I personally like to include the optional "extern" keyword.)On 01/12/2024 15:23, Bart wrote:You said you didn't want a list of declarations to maintain for static functions within a module.>Such lists might have been helpful to some people decades ago, when editors were more primitive. If I need a list of functions in a file (maybe it's someone else's code, or old code of mine), any programmer's editor or IDE will give me it - updated correctly in real-time, and not out of sync.>
Why isn't this a problem for exported/shared functions?
>
That is, for all sorts of functions and variables declared in headers where there is a declaration in header, and a definition in some 'home' module.
>
What do you mean here?
But for non-static functions, which are shared via a header, you /need/ such a list to be maintained:
prog.h: int F(int);I can't speak for how you or anyone else writes code, but my code would never look like that in practice. (Obviously I know what you wrote is a quick example, not real code.) A local static function might have a small, simple name - it is of very local scope, so like local variables its purpose can be seen clearly from its definition and use. An exported function, on the other hand, will have a good name, properly named parameters, carefully chosen parameter types, comments, and a position in the header to suit the structure of the code. Thus "F" and "G" are very different in my code.
prog.c: #include "prog.h"
static int G(int a);
int F(int a) {return 0;}
static int G(int a) {return 0;}
Here, you object to having to maintain the declaration for G, but you still need to do so for F, and inside a separate file.
The declaration for F could also get out of sync, but you don't consider that a problem?It would be a problem if it happened, yes.
And if it isn't because your tools help with this, then they can help with G too.As I explained earlier, they /can/ help with some sync errors in lists of static forward declarations.
Agreed. C does not have a real module scheme as such. But it supports getting similar effects - you just have to be disciplined in the way you write your headers. This has the disadvantage of being less consistent than, say, Pascal or Modula 2, especially if the programmer is not disciplined. And it has the advantage in flexibility - I have a scheme that I like and that works well for the kind of code I work with, but other people prefer other schemes. It's easy to fall into the trap of "my way is the right way", especially when you make your own language and you are the only user, but there is always a balance to be sought between consistency and flexibility.I certainly consider it a weakness in C that you don't have clear requirements and limitations for what can be in a header or a C file, or how things can be mixed and matched. Keeping code clear and well-ordered therefore requires discipline and standardised arrangement of code and declarations. Different kinds of projects will have different requirements here, but for my own code I find it best to be strict that for any C file "file.c", there will be a header "file.h" which contains "extern" declarations of any exported functions or data, along with any type declarations needed to support these. My tools will warn on any mismatches, such as non-static functions without a matching "extern" declaration. They can't catch everything - the way C is built up, there is no distinction between external declarations that should be defined in the same module and ones that are imported from elsewhere.Yes, this is why a module scheme (such as the kind I use) is invaluable.
In the example above, you'd define both F and G in one place. There is no header and there are no separate declarations.To me, it is absolutely vital that the importing unit can only see the identifiers that were explicitly exported. It is also absolutely vital (and this is a critical missing feature for C - and a good reason to switch to C++ even if you use no other feature of that language) that the imported identifiers be in their own namespace so that they do not conflict with identifiers in the importing unit. If the language provides a feature for importing the external identifiers directly into the current unit's namespace, then it has to allow selective import of identifiers - otherwise all concepts of scalability and modularity go out the window.
If another module wishes to use F, then it imports the whole module that defines F.
Some schemes can selectively import individual functions, but to me that's pointless micro-managing.
In my scheme, it is not even necessary for individual modules to explicitly import each other: a simple list of modules is provided in one place, and they will automatically import each others' exported entities (which include functions, variables, types, enums, structs, named constants, and macros).That sounds, frankly, utterly terrible for anyone who worked with other people.
Les messages affichés proviennent d'usenet.