C语言从命令行提取程序名

在一些项目中,我们需要在项目的bin目录中生成可执行文件,除了参数处理外,有个很重要的过程就是获取程序名,如下是比较严谨的获取程序名的方式,来源于PostgreSQL。

/*
 * Extracts the actual name of the program as called stripped of .exe suffix if any
 */
const char *get_progname(const char *argv0)
{
	const char *nodir_name;
	char	   *progname;

	nodir_name = last_dir_separator(argv0);
	if (nodir_name)
		nodir_name++;
	else
		nodir_name = skip_drive(argv0);

	/*
	 * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
	 * called only once.
	 */
	progname = strdup(nodir_name);
	if (progname == NULL)
	{
		fprintf(stderr, "%s: out of memory\n", nodir_name);
		abort();				/* This could exit the postmaster */
	}

#if defined(__CYGWIN__) || defined(WIN32)
	/* strip ".exe" suffix, regardless of case */
	if (strlen(progname) > sizeof(EXE) - 1 &&
		pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
		progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
#endif

	return progname;
}



/*
 *	last_dir_separator
 *
 * Find the location of the last directory separator, return
 * NULL if not found.
 */
char *last_dir_separator(const char *filename)
{
	const char *p,
			   *ret = NULL;

	for (p = skip_drive(filename); *p; p++)
		if (IS_DIR_SEP(*p))
			ret = p;
	return unconstify(char *, ret);
}


/*
 * skip_drive
 *
 * On Windows, a path may begin with "C:" or "//network/".  Advance over
 * this and point to the effective start of the path.
 */
#ifdef WIN32

static char *skip_drive(const char *path)
{
	if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
	{
		path += 2;
		while (*path && !IS_DIR_SEP(*path))
			path++;
	}
	else if (isalpha((unsigned char) path[0]) && path[1] == ':')
	{
		path += 2;
	}
	return (char *) path;
}
#else
#define skip_drive(path)	(path)
#endif


/*
 *	is_absolute_path and IS_DIR_SEP
 *
 *	By using macros here we avoid needing to include path.c in libpq.
 */
#ifndef WIN32
#define IS_DIR_SEP(ch) IS_NONWINDOWS_DIR_SEP(ch)
#define is_absolute_path(filename) is_nonwindows_absolute_path(filename)
#else
#define IS_DIR_SEP(ch) IS_WINDOWS_DIR_SEP(ch)
#define is_absolute_path(filename) is_windows_absolute_path(filename)
#endif

#define IS_NONWINDOWS_DIR_SEP(ch)	((ch) == '/')
#define is_nonwindows_absolute_path(filename) \
( \
	IS_NONWINDOWS_DIR_SEP((filename)[0]) \
)

#define IS_WINDOWS_DIR_SEP(ch)	((ch) == '/' || (ch) == '\\')
/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */
#define is_windows_absolute_path(filename) \
( \
	IS_WINDOWS_DIR_SEP((filename)[0]) || \
	(isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \
	 IS_WINDOWS_DIR_SEP((filename)[2])) \
)

/*
 * Macro that allows to cast constness and volatile away from an expression, but doesn't
 * allow changing the underlying type.  Enforcement of the latter
 * currently only works for gcc like compilers.
 *
 * Please note IT IS NOT SAFE to cast constness away if the result will ever
 * be modified (it would be undefined behaviour). Doing so anyway can cause
 * compiler misoptimizations or runtime crashes (modifying readonly memory).
 * It is only safe to use when the result will not be modified, but API
 * design or language restrictions prevent you from declaring that
 * (e.g. because a function returns both const and non-const variables).
 *
 * Note that this only works in function scope, not for global variables (it'd
 * be nice, but not trivial, to improve that).
 */
#if defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P)
#define unconstify(underlying_type, expr) \
	(StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), const underlying_type), \
					  "wrong cast"), \
	 (underlying_type) (expr))
#define unvolatize(underlying_type, expr) \
	(StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), volatile underlying_type), \
					  "wrong cast"), \
	 (underlying_type) (expr))
#else
#define unconstify(underlying_type, expr) \
	((underlying_type) (expr))
#define unvolatize(underlying_type, expr) \
	((underlying_type) (expr))
#endif


/*
 * Macros to support compile-time assertion checks.
 *
 * If the "condition" (a compile-time-constant expression) evaluates to false,
 * throw a compile error using the "errmessage" (a string literal).
 *
 * gcc 4.6 and up supports _Static_assert(), but there are bizarre syntactic
 * placement restrictions.  These macros make it safe to use as a statement
 * or in an expression, respectively.
 *
 * Otherwise we fall back on a kluge that assumes the compiler will complain
 * about a negative width for a struct bit-field.  This will not include a
 * helpful error message, but it beats not getting an error at all.
 */
#ifndef __cplusplus
#ifdef HAVE__STATIC_ASSERT
#define StaticAssertStmt(condition, errmessage) \
	do { _Static_assert(condition, errmessage); } while(0)
#define StaticAssertExpr(condition, errmessage) \
	((void) ({ StaticAssertStmt(condition, errmessage); true; }))
#else							/* !HAVE__STATIC_ASSERT */
#define StaticAssertStmt(condition, errmessage) \
	((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
#define StaticAssertExpr(condition, errmessage) \
	StaticAssertStmt(condition, errmessage)
#endif							/* HAVE__STATIC_ASSERT */
#else							/* C++ */
#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410
#define StaticAssertStmt(condition, errmessage) \
	static_assert(condition, errmessage)
#define StaticAssertExpr(condition, errmessage) \
	({ static_assert(condition, errmessage); })
#else
#define StaticAssertStmt(condition, errmessage) \
	do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0)
#define StaticAssertExpr(condition, errmessage) \
	((void) ({ StaticAssertStmt(condition, errmessage); }))
#endif
#endif							/* C++ */


/*
 * Case-independent comparison of two null-terminated strings.
 */
int
pg_strcasecmp(const char *s1, const char *s2)
{
	for (;;)
	{
		unsigned char ch1 = (unsigned char) *s1++;
		unsigned char ch2 = (unsigned char) *s2++;

		if (ch1 != ch2)
		{
			if (ch1 >= 'A' && ch1 <= 'Z')
				ch1 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(ch1) && isupper(ch1))
				ch1 = tolower(ch1);

			if (ch2 >= 'A' && ch2 <= 'Z')
				ch2 += 'a' - 'A';
			else if (IS_HIGHBIT_SET(ch2) && isupper(ch2))
				ch2 = tolower(ch2);

			if (ch1 != ch2)
				return (int) ch1 - (int) ch2;
		}
		if (ch1 == 0)
			break;
	}
	return 0;
}

/* msb for char */
#define HIGHBIT					(0x80)
#define IS_HIGHBIT_SET(ch)		((unsigned char)(ch) & HIGHBIT)

关于静态编译检查:

#include <stdio.h>
#include <stdbool.h>
#define StaticAssertStmt(condition, errmessage) \
    do { _Static_assert(condition, errmessage); } while(0)
#define StaticAssertExpr(condition, errmessage) \
    ((void) ({ StaticAssertStmt(condition, errmessage); true; }))

#define unconstify(underlying_type, expr) \
    (StaticAssertExpr(__builtin_types_compatible_p(__typeof__(expr), const underlying_type), \
                      "wrong cast"), \
     (underlying_type)(expr))

int main() {
    const int a = 42;
    int b = unconstify(int, a); // 通过静态编译检查
    printf("b = %d\n", b);

    // 下面这行会导致静态编译错误,因为double和int类型不兼容
    double c = unconstify(double, a); // 静态编译检查失败

    return 0;
}

在这里插入图片描述

在这里插入图片描述

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要完成一个带数据库的 C 语言程序,您需要执行以下步骤: 1. 选择合适的数据库管理系统,例如 MySQL、SQLite 或 PostgreSQL。 2. 安装选择的数据库管理系统和对应的 C 语言驱动程序,如 libmysqlclient。 3. 编写 C 程序,连接到数据库,执行 SQL 查询并处理结果。 4. 创建数据库表并插入数据。 5. 编写代码以从数据库中读取数据并进行处理。 6. 在 C 程序中实现增删改查等常见的数据库操作。 7. 编译和运行 C 程序,验证数据库操作是否正确。 8. 调试和优化代码,以提高程序的性能和可靠性。 这只是一个大致的指导,具体实现过程可能因您选择的数据库管理系统和 C 语言驱动程序而异。 ### 回答2: 要完成一个带数据库的C语言程序,首先需要确定要使用的数据库系统,比如MySQL、SQLite或者PostgreSQL等。然后按照以下步骤进行操作: 1. 安装数据库系统:根据选择的数据库系统,下载并安装相应的软件包,确保数据库系统在本地计算机上正确安装并可用。 2. 创建数据库:打开数据库系统的命令行界面或者图形化工具,使用SQL语句创建一个新的数据库。例如,可以使用CREATE DATABASE语句在MySQL中创建一个新的数据库。 3. 设计数据表:根据需求设计数据表结构。使用SQL语句定义表的字段、数据类型、主键、外键等。例如,可以使用CREATE TABLE语句在创建的数据库中创建一个新的表。 4. 连接数据库:在C语言程序中,使用数据库系统提供的API函数来连接到已创建的数据库。一般情况下,可以使用库文件提供的函数来连接到数据库并返回一个连接对象,以便后续操作。 5. 执行SQL语句:使用C语言程序调用数据库系统提供的API函数,执行需要的SQL语句,如插入、更新、删除或查询等操作。可以使用预处理语句来减少SQL注入的风险。例如,可以使用INSERT语句向数据表中插入新的数据。 6. 处理数据库查询结果:当执行查询语句时,数据库系统会返回结果集。在C语言程序中,需要使用API函数来获取查询结果,并进行相应的处理。可以使用循环语句和条件语句来遍历结果集,提取出需要的数据。 7. 关闭数据库连接:在程序使用完毕后,需要使用数据库系统提供的API函数来关闭数据库连接,释放资源。 通过以上步骤,可以完成一个基本的带数据库的C语言程序。不同的数据库系统和操作系统可能有所差异,具体的实现方式需要参考对应的文档和示例代码。 ### 回答3: 要完成一个带数据库的C语言程序,需要以下几个步骤: 1. 设计数据库结构:首先,确定你的应用需要存储哪些数据,并设计数据库表格来保存这些数据。定义表格的字段(列)和属性,例如数据类型、长度和约束条件等。 2. 编写数据库连接代码:在C语言中,可以使用数据库接口(例如ODBC、JDBC或其他数据库封装库)来连接数据库。根据所选择的数据库类型和库文件,你需要在代码中初始化数据库连接并处理连接状态,确保与数据库的连接正常建立。 3. 编写SQL查询语句和操作代码:使用C语言编写SQL查询语句和数据库操作代码。例如,查询数据、插入、更新或删除数据等,可以使用适当的SQL语句和数据库相关函数执行这些操作。你还可以编写其他功能代码,例如创建表格、删除表格等。 4. 执行数据库操作:通过调用数据库操作代码,执行预先定义好的数据库查询和操作,与数据库进行交互。你可以根据需要执行单个操作或批量操作,预处理和绑定参数以提高效率和安全性。 5. 错误处理和异常处理:在程序中添加错误处理和异常处理机制,以便在数据库操作期间出现错误或故障时进行适当的处理。这可以包括捕获异常、日志记录和错误信息提示。 6. 其他功能和界面设计:根据你的需求,可以进一步添加其他功能和用户界面设计。例如,提供用户输入界面、数据展示界面、数据导出等。 7. 测试和调试:在程序完成后,进行测试和调试。验证数据库操作的正确性和稳定性,确保程序能够正常运行并与数据库互动。 总之,完成一个带数据库的C语言程序需要根据需要进行数据库结构设计、编写数据库连接代码、编写SQL查询和操作代码、执行操作、处理错误、添加其他功能和界面设计,最后进行测试和调试,以确保程序的正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值