|
It is, quite probably.
fgets (not std::string constructor as I initially posted) is behaving different if I set different options for Optimization and Runtime Library in MSVS2005.
I can't make Release work like Debug though, even setting the same options.
|
|
|
|
|
Hi,
I'm working on a small libarary that will parse and modify a certain type of configuration file. As suggested by wise people (I think) I'd like to hide away the implementation and offer the user a set of functions to use the library.
I have questions mainly philosophical or concerning style. I'll put here my idea and it'd be very nice to get your opinions on it.
#ifndef CONFIGFILEAPI_H_INCLUDED
#define CONFIGFILEAPI_H_INCLUDED
#include <string>
#include <vector>
namespace cfgFileLib
{
std::string openConfigFile (const std::string & fileName);
bool isDefined (const std::string & symbol);
int howMany (const std::string & symbol);
bool getBool (const std::string & symbol);
int getInt (const std::string & symbol);
double getDouble (const std::string & symbol);
std::string getString (const std::string & symbol);
std::vector <bool> getAllBool (const std::string & symbol);
std::vector <int> getAllInt (const std::string & symbol);
std::vector <double> getAllDouble (const std::string & symbol);
std::vector <std::string> getAllString (const std::string & symbol);
}
#endif
- Does this design make sense in general?
- Do I put it all whithin a namespace?
modified 6-Aug-14 8:51am.
|
|
|
|
|
Have a look at Boost.PropertyTree[^]
I think it's a well designed library - it's worth taking a look at it's implementation.
>> Does this design make sense in general?
Normally you would create a class that is able to hold more than one configuration entry, and then something representing the various kinds of entries.
>> Do I put it all whithin a namespace?
That's usually a good idea
Best regards
Espen Harlinn
Espen Harlinn
Chief Architect - Powel AS
Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
|
|
|
|
|
Thanks Espen. I'll take a look at Boost.PropertyTree
I didn't get what you meant by
Espen Harlinn wrote: Normally you would create a class that is able to hold more than one configuration entry, and then something representing the various kinds of entries.
|
|
|
|
|
Something structured somewhat like this:
class ConfigEntry
{
};
class ConfigNode : public ConfigEntry
{
typedef std::map<std::string,std::shared_ptr<ConfigEntry> > EntryMap;
EntryMap entryMap_;
};
class ConfigValue : public ConfigEntry
{
};
class StringConfigValue : public ConfigValue
{
std::string value_;
};
class IntConfigValue : public ConfigValue
{
int value_;
};
class ConfigFile : public ConfigNode
{
};
This way the EntryMap can hold std::string, int and nested ConfigNode objects.
Espen Harlinn
Chief Architect - Powel AS
Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
|
|
|
|
|
If you're using this in C++ only, seems ok (let alone the preferences).
However, I'd do this:
- no namespace exports; be wary of linker decorations
- export just the needed functions, not all (i.e. the "public" interface)
- separate helpers from actors (i.e openConfigFile, isDefined vs getBool, getInt)
- do not return std::string or others from functions; rather, return just simple testable values (int, bool) and change to
bool openConfigFile(const std::string& filename, std::string& result); (or std::string* result)
- if you'll get this used in other places, favor a C-like interface and do the plumbing code, such as
BOOL WINAPI OpenConfigFileA(LPCSTR fileName, LPSTR* result);
or use VARIANTs is needed in VBS.
- or favor the COM-like exports with just structs with virtual pure functions and DllGetClassObject-like creators.
There are many things to consider. I'm using sometimes even paper and pen to weight all these.
|
|
|
|
|
Hi I am beginner in c++ , I have a console project and want to convert it to windows application , after 6-7 days trying I couldn't convert it and when I compile project I have many more errors
This is my console project: http:
Please convert it for me to windows gui application to help me thanks a lot
|
|
|
|
|
|
Don't convert console apps, rather follow this short list:
1. Make sure key logic is not in same file as main.
2. Create a dialog app using Visual Studio
3. Add files from step 1
4. Hook up functionality
Of course 4 is the complicated part since how Windowed apps work is different from Console. As previously suggested, if you don't know how windowed apps work, get educated. Petzold isn't a bad starting point, though will only take you so far.
|
|
|
|
|
Just another homework, no effort from poster, just "I can't do it" and a link.
We're supposed to invest time and effort to offer you solutions for free, in our time, so you can get an A and forget about C++ or something? RTFM.
|
|
|
|
|
in this code?from where i need to understand that is deleting something?
void Database_delete(struct Connection *conn, int id)
{
struct Address addr = {.id = id, .set = 0};
conn->db->rows[id] = addr;
|
|
|
|
|
As far as I know, this is not valid C++ code.
THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?!
-- C++ FQA Lite
|
|
|
|
|
|
Yes, you are right.
THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?!
-- C++ FQA Lite
|
|
|
|
|
This[^] thread might help. It looks as though there are members of the Address struct one called set and it's getting initialized to 0, and another called id and it's getting initialized to the given integer id.
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
|
|
|
|
|
yes,but by the name of function says(database_delete),this function must delete something,and i don't know how it is deleting something
|
|
|
|
|
Just a guess, perhaps set is some kind of flag marking a record as inactive or something, as opposed to actually deleting a record. What a functions name is and what it actually does may be two different things. What's needed here I believe is some useful comments.
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
|
|
|
|
|
can i give you the entire code?maybe you will find my answer
|
|
|
|
|
This ties into the code you posted below. Specifically, it's related to this method:
void Database_set(struct Connection *conn, int id, const char *name, const char *email)
{
struct Address *addr = &conn->db->rows[id];
if(addr->set) die("Already set, delete it first");
addr->set = 1; Basically, it looks like it's controlling whether or not you've already set the value in this row - so, to set a value here, you would call Database_delete first, which changes the value in id from 1 to 0, which means that the rest of Database_set can continue.
|
|
|
|
|
i understand now,thank you very much!
|
|
|
|
|
You're welcome.
|
|
|
|
|
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define MAX_DATA 512
#define MAX_ROWS 100
struct Address {
int id;
int set;
char name[MAX_DATA];
char email[MAX_DATA];
};
struct Database {
struct Address rows[MAX_ROWS];
};
struct Connection {
FILE *file;
struct Database *db;
};
void die(const char *message)
{
if(errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
void Address_print(struct Address *addr)
{
printf("%d %s %s\n",
addr->id, addr->name, addr->email);
}
void Database_load(struct Connection *conn)
{
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
if(rc != 1) die("Failed to load database.");
}
struct Connection *Database_open(const char *filename, char mode)
{
struct Connection *conn = malloc(sizeof(struct Connection));
if(!conn) die("Memory error");
conn->db = malloc(sizeof(struct Database));
if(!conn->db) die("Memory error");
if(mode == 'c') {
conn->file = fopen(filename, "w");
} else {
conn->file = fopen(filename, "r+");
if(conn->file) {
Database_load(conn);
}
}
if(!conn->file) die("Failed to open the file");
return conn;
}
void Database_close(struct Connection *conn)
{
if(conn) {
if(conn->file) fclose(conn->file);
if(conn->db) free(conn->db);
free(conn);
}
}
void Database_write(struct Connection *conn)
{
rewind(conn->file);
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
if(rc != 1) die("Failed to write database.");
rc = fflush(conn->file);
if(rc == -1) die("Cannot flush database.");
}
void Database_create(struct Connection *conn)
{
int i = 0;
for(i = 0; i < MAX_ROWS; i++) {
// make a prototype to initialize it
struct Address addr = {.id = i, .set = 0};
// then just assign it
conn->db->rows[i] = addr;
}
}
void Database_set(struct Connection *conn, int id, const char *name, const char *email)
{
struct Address *addr = &conn->db->rows[id];
if(addr->set) die("Already set, delete it first");
addr->set = 1;
// WARNING: bug, read the "How To Break It" and fix this
char *res = strncpy(addr->name, name, MAX_DATA);
// demonstrate the strncpy bug
if(!res) die("Name copy failed");
res = strncpy(addr->email, email, MAX_DATA);
if(!res) die("Email copy failed");
}
void Database_get(struct Connection *conn, int id)
{
struct Address *addr = &conn->db->rows[id];
if(addr->set) {
Address_print(addr);
} else {
die("ID is not set");
}
}
void Database_delete(struct Connection *conn, int id)
{
struct Address addr = {.id = id, .set = 0};
conn->db->rows[id] = addr;
}
void Database_list(struct Connection *conn)
{
int i = 0;
struct Database *db = conn->db;
for(i = 0; i < MAX_ROWS; i++) {
struct Address *cur = &db->rows[i];
if(cur->set) {
Address_print(cur);
}
}
}
int main(int argc, char *argv[])
{
if(argc < 3) die("USAGE: ex17 <dbfile> <action> [action params]");
char *filename = argv[1];
char action = argv[2][0];
struct Connection *conn = Database_open(filename, action);
int id = 0;
if(argc > 3) id = atoi(argv[3]);
if(id >= MAX_ROWS) die("There's not that many records.");
switch(action) {
case 'c':
Database_create(conn);
Database_write(conn);
break;
case 'g':
if(argc != 4) die("Need an id to get");
Database_get(conn, id);
break;
case 's':
if(argc != 6) die("Need id, name, email to set");
Database_set(conn, id, argv[4], argv[5]);
Database_write(conn);
break;
case 'd':
if(argc != 4) die("Need id to delete");
Database_delete(conn, id);
Database_write(conn);
break;
case 'l':
Database_list(conn);
break;
default:
die("Invalid action, only: c=create, g=get, s=set, d=del, l=list");
}
Database_close(conn);
return 0;
}
|
|
|
|
|
Alex Sturza wrote: Database_close(conn);
return 0;
} Are you sure that is your question?
|
|
|
|
|
my bad,sry about you wasted time to read my code )
|
|
|
|
|
Just try reading things a bit before posting here. Your other question (in the C# forum) is similar.
|
|
|
|
|