D - [Beginner] My first program - Access Violation :-(
- Dave Sieber (25/25) Mar 25 2004 Ok, I'm a complete beginner, and need some guidance, if there are any ki...
- J Anderson (5/31) Mar 25 2004 This is the best group.
- J Anderson (18/41) Mar 25 2004 Guess I should explain why. D strings are not null terminated like c.
- Dave Sieber (16/34) Mar 25 2004 Thank you, very fast response! I understand now what is going on, I'm j...
- SL (4/8) Mar 25 2004 There's a printf in object? O.o
- Dave Sieber (32/35) Mar 25 2004 Yes, it's only when there are type mismatches in the args which the
- Russ Lewis (77/77) Mar 25 2004 J Anderson,
- Dave Sieber (21/22) Mar 25 2004 Wow, Russ, thank you for the excellent explanation! You should get that...
- J Anderson (4/13) Mar 25 2004 It should indeed. Russ?
- Russ Lewis (3/19) Apr 07 2004 I'm way buried in work...if somebody else wants to post it, that's great...
- J C Calvarese (4/23) Apr 08 2004 I posted it at:
- Brad Anderson (5/7) Mar 25 2004 Try the Wiki also...
- Dave Sieber (4/9) Mar 25 2004 Thank you, I'm visiting it now.
Ok, I'm a complete beginner, and need some guidance, if there are any kind souls out there. I've created my first program. It compiles with no errors. But when I run it, I get an Access Violation. It looks like a problem with printf(), but I don't know what is wrong with it. Here's the program: ========================== import std.compiler; int main() { // this works printf(std.compiler.name); // this gets an Access Violation printf("%s\n", std.compiler.name); return 0; } ========================== I have some other questions about this short program, but I'd like to do one at a time. Would a group for beginners be a good idea? I see a lot of technical discussion here, and I feel my simple-minded question is out of place. Perhaps something like D.learn or D.help? Or, if it's okay to ask beginner questions here, I'll carry on. -- dave
Mar 25 2004
Dave Sieber wrote:Ok, I'm a complete beginner, and need some guidance, if there are any kind souls out there. I've created my first program. It compiles with no errors. But when I run it, I get an Access Violation. It looks like a problem with printf(), but I don't know what is wrong with it. Here's the program: ========================== import std.compiler; int main() { // this works printf(std.compiler.name); // this gets an Access Violation printf("%s\n", std.compiler.name); //This lineprintf("%.*s\n", std.compiler.name); //Very common mistakereturn 0; } ==========================I have some other questions about this short program, but I'd like to do one at a time. Would a group for beginners be a good idea? I see a lot of technical discussion here, and I feel my simple-minded question is out of place. Perhaps something like D.learn or D.help? Or, if it's okay to ask beginner questions here, I'll carry on.This is the best group. -- -Anderson: http://badmama.com.au/~anderson/
Mar 25 2004
J Anderson wrote:Dave Sieber wrote:Guess I should explain why. D strings are not null terminated like c. D does it's best to convert D string into zero-terminated strings when using a C like function. However in the case of printf there is no way to tell that the conversion is needed (generally). Therefore you use the .* part which happens to mean the length followed by the string pointer, which is what D strings are. D string (array) struct array { uint length; char* array; //size length } C String char* array; //size length + 1 where last character is zero Hope that helps. -- -Anderson: http://badmama.com.au/~anderson/Ok, I'm a complete beginner, and need some guidance, if there are any kind souls out there. I've created my first program. It compiles with no errors. But when I run it, I get an Access Violation. It looks like a problem with printf(), but I don't know what is wrong with it. Here's the program: ========================== import std.compiler; int main() { // this works printf(std.compiler.name); // this gets an Access Violation printf("%s\n", std.compiler.name); //This lineprintf("%.*s\n", std.compiler.name); //Very common mistake
Mar 25 2004
J Anderson <REMOVEanderson badmama.com.au> wrote:Thank you, very fast response! I understand now what is going on, I'm just not sure I like it :-) You know, when you start a new language and you (perhaps subconsciously) expect things to work as you're used to with some previous language -- it takes a little while, and a few bone-headed errors like mine, before it sinks in and becomes natural. Meanwhile, you curse the new language <BG> I had one other question, but I think I have got it on my own: I was wondering where printf() came from, but std.c.stdio is implicitly imported, yes? And according to phobos.html, it is the only symbol defined in that module. New question: what is the difference (if any) between std.c.stdio's printf(), and object's static printf() ? And why is it there in object? Isn't the one in std.c.stdio available anywhere you want to use it? -- daveprintf("%.*s\n", std.compiler.name); //Very common mistakeGuess I should explain why. D strings are not null terminated like c. D does it's best to convert D string into zero-terminated strings when using a C like function. However in the case of printf there is no way to tell that the conversion is needed (generally). Therefore you use the .* part which happens to mean the length followed by the string pointer, which is what D strings are. D string (array) struct array { uint length; char* array; //size length } C String char* array; //size length + 1 where last character is zero
Mar 25 2004
Dave Sieber wrote:New question: what is the difference (if any) between std.c.stdio's printf(), and object's static printf() ? And why is it there in object? Isn't the one in std.c.stdio available anywhere you want to use it?There's a printf in object? O.o I don't have a clue why, myself, but I can say that printf works quite wonderfully for me, so long as I avoid %s (and use %.*s instead.) :P
Mar 25 2004
SL <shadowlord13 users.sourceforge.net> wrote:There's a printf in object? O.oThe docs say it's there. I haven't tried to use it.I don't have a clue why, myself, but I can say that printf works quite wonderfully for me, so long as I avoid %s (and use %.*s instead.) :PYes, it's only when there are type mismatches in the args which the compiler can't detect that it is problematic. In C++ code, when programming windows, you still have to do a lot of printf-style calls, and I've taken up the practice of always doing something like this (from memory): inline char const *charptr(char const *p) { return p; } inline char const *charptr(std::string const& s) { return s.c_str(); } // ... likewise for anything else that can be converted // to a character pointer... // then you could do something like this: template <typename T> inline void printit(T const& t) { printf("%s\n", charptr(t)); } IOW, I *always* use charptr() on any "%s" argument to a printf-style function. That way, if I ever have reason to change the argument type (say, from 'std::string const&' to 'char const *') the call still works. And if I change the argument type to something that cannot be converted to 'const char *' via charptr(), I know immediately on the next compile, and I can address it. This has saved me a number of times, especially when you have several team members working on code and they are not all conscientious about their code quality (quite common, at least where I've worked). -- dave
Mar 25 2004
J Anderson, What you've explained so far is correct; I just wanted to add a bit to it. Dave, You may eventually find yourself wondering why printf(std.compiler.name); works while printf("%.*s\n", std.compiler.name); doesn't. A C-library printf() will be expecting that the format string (the first argument) is a null-terminated string. But if D doesn't null-terminate strings, and if arrays are actually two numbers (length and pointer), then how can it work? The short answer is that Walter has put in a lot of good default things that make your life easier. The long answer is... printf() is declared in object.d like this: extern (C) int printf(char *, ...); extern (C) - means that this is a C function, which is implemented in some other file (usually, in the standard library). char* - means, of course, that the first argument (the format string) MUST be a char*. ... - means, like C, that this will accept any number of arguments (it is a varargs function). In your first call: printf(std.compiler.name); std.compiler.name is defined in std/compiler.d as: char[] name = "Digital Mars D"; That is, the type is a dynamic array, but it is initialized with a certain constant string. When you use constant strings like this, Walter automatically places a null byte after the string. It doesn't count in the length of the array, but a C function that reads the array will see the null terminator it expects. The other magic that happens is that when you pass char[] into a function that expects char*, the compiler performs an implicit cast. So when you call printf(std.compiler.name); this implicit cast happens: printf((char*)std.compiler.name); which basically means this is happening: printf(&std.compiler.name[0]); So, the argument that printf() sees is a pointer value which points to the start of the string; since Walter added an invisible null at the end of the string, printf() terminates nicely. But try this, and it will break: printf("std.compiler.name = "~std.compiler.name); When you concatenate the two arrays with the ~ operator, the compiler makes a copy of the two and returns the concatenated string in a new array someplace. This operation does NOT get the automatic null terminator. So printf will run off forever, printing garbage, until it hits a 0 by pure luck or until you get an Access Violation (segfault). So why doesn't the compiler implicitly cast the array in the second call? printf("%s\n", std.compiler.name); In this case, the compier doesn't know the type that printf() expects for the second argument. So it just passes the array onto the stack, unaltered. printf("%s\n", std.compiler.name); is more or less the same as calling this: printf("%s\n", std.compiler.name.length, (char*)std.compiler.name); Your choices are to use the %.s, or to use this: printf("%s\n", (char*)std.compiler.name); The %.s is probably better in most cases, but not all C libraries support it. The cast is supported everywhere, but doesn't work if the string isn't null terminated. So how do you print an arbitrary string in a portable manner? I use this code often: char[] foo; printf("%s\n", (char*)(foo~\0)); which just appends a null character onto the string, then casts the string to a char* so that printf() gets what it expects. Happily, Walter provides the toStringz() function in std.string which does the same: char[] foo; printf("%s\n", toStringz(foo)); ...plus Walter's function has some smarts in it to avoid doing unneccesary copies. So, in summary: * The compiler adds nulls into the memory after constant strings, but when you build a string at runtime these nulls don't exist * The compiler implicitly casts char[] to char*, when it knows that this is necessary
Mar 25 2004
Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:<snip for brevity>Wow, Russ, thank you for the excellent explanation! You should get that onto the wiki so that others can benefit from it, especially noobs like me :-) I can see that I'll just need to get to the point of "thinking in D", just as I now do with C++. It's not hard (as your explanation shows), but you do need to make sure you understand what it is doing so that you can use it to your advantage. A couple comments: I like the toStringz() solution the best, as this mirrors what I do in C++ to avoid any "surprises" with a printf-style function call. Also, just to mention in passing something which I'm sure you already know: one should never pass a string in any form to printf() (in D or C/C++) without a "%s" format specifier. Let's say you've asked the user for some input, and then you're going to output it: printf(usersInput); If the user typed a "%s" somewhere in his input, printf() will interpret that as a format string, and will end up trying to print something from a misinterpreted stack -- crashville, Daddy-o! -- dave
Mar 25 2004
Dave Sieber wrote:Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:It should indeed. Russ? -- -Anderson: http://badmama.com.au/~anderson/<snip for brevity>Wow, Russ, thank you for the excellent explanation! You should get that onto the wiki so that others can benefit from it, especially noobs like me :-)
Mar 25 2004
I'm way buried in work...if somebody else wants to post it, that's great with me. :) J Anderson wrote:Dave Sieber wrote:Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:It should indeed. Russ?<snip for brevity>Wow, Russ, thank you for the excellent explanation! You should get that onto the wiki so that others can benefit from it, especially noobs like me :-)
Apr 07 2004
In article <c51e7s$ke9$1 digitaldaemon.com>, Russ Lewis says...I'm way buried in work...if somebody else wants to post it, that's great with me. :)I posted it at: http://www.wikiservice.at/d/wiki.cgi?HowTo/printf#charvschar JCJ Anderson wrote:Dave Sieber wrote:Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:It should indeed. Russ?<snip for brevity>Wow, Russ, thank you for the excellent explanation! You should get that onto the wiki so that others can benefit from it, especially noobs like me :-)
Apr 08 2004
Try the Wiki also... http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage and specifically, the FAQ: http://www.prowiki.org/wiki4d/wiki.cgi?FaqRoadmap J Anderson wrote:This is the best group.
Mar 25 2004
Brad Anderson <brad sankaty.dot.com> wrote:Try the Wiki also... http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage and specifically, the FAQ: http://www.prowiki.org/wiki4d/wiki.cgi?FaqRoadmapThank you, I'm visiting it now. -- dave
Mar 25 2004