C 如何确定指针是否等于数组的元素?
我有一个“工程”如预期,但可能有C 如何确定指针是否等于数组的元素?,c,arrays,pointers,language-lawyer,C,Arrays,Pointers,Language Lawyer,我有一个“工程”如预期,但可能有 代码有一个大小相同的数组char数组,称为GP2\u格式[]。要检测指针格式是否与其中一个元素GP2_format[][0]的地址具有相同的值,下面的代码简单测试了指针是否是=最小的元素,如果您希望符合C标准,则您的选项是: 执行单个==或=针对目标范围内的每个指针进行测试 如果这是一个非常大的集合,您可以使用哈希表或搜索树或其他方法来加快速度 重新设计代码,使其不需要此检查 “可能有效”的方法是将所有值强制转换为uintptru\t,然后进行关系比较
代码有一个大小相同的数组
char
数组,称为GP2\u格式[]
。要检测指针格式
是否与其中一个元素GP2_format[][0]
的地址具有相同的值,下面的代码简单测试了指针是否是=
最小的元素,如果您希望符合C标准,则您的选项是:
- 执行单个
或==
=代码>针对目标范围内的每个指针进行测试
- 如果这是一个非常大的集合,您可以使用哈希表或搜索树或其他方法来加快速度
- 重新设计代码,使其不需要此检查
“可能有效”的方法是将所有值强制转换为
uintptru\t
,然后进行关系比较。如果系统具有具有绝对顺序的内存模型,则应定义uintptru\t
并保留该顺序;如果它没有这样的模型,那么关系比较的想法无论如何也不会起作用。如果你想遵守C标准,那么你的选择是:
- 执行单个
或==
=代码>针对目标范围内的每个指针进行测试
- 如果这是一个非常大的集合,您可以使用哈希表或搜索树或其他方法来加快速度
- 重新设计代码,使其不需要此检查
“可能有效”的方法是将所有值强制转换为
uintptru\t
,然后进行关系比较。如果系统具有具有绝对顺序的内存模型,则应定义uintptru\t
并保留该顺序;如果它没有这样一个模型,那么关系比较的想法无论如何也不会起作用。这不是对所述问题的回答,而是对根本问题的回答
除非我弄错了,否则整个问题都可以通过将GP_格式
设置为字符串来避免。通过这种方式,问题简化为检查指针是否指向已知字符串,而这不是UB。(如果是,那么使用UB来查找字符并计算其在字符串中的索引将是完全愚蠢的。在我看来,这将是标准中的一个严重缺陷。再说一次,我不是语言律师,只是一个试图编写健壮、可移植C的程序员。幸运的是,标准声明它是为了帮助像m这样的人而编写的e、 而不是编译器编写人员,他们希望在标准技术允许的情况下,通过生成垃圾来避免做繁重的工作。)
下面是我心目中的方法的完整示例。这也适用于clang-3.5,因为我目前使用的机器上最新的GCC是4.8.4版,它不支持\u Generic()
。如果使用不同版本的clang或gcc,请相应地更改Makefile
中的第一行,或运行例如makecc=gcc
首先,Makefile
:
CC := clang-3.5
CFLAGS := -Wall -Wextra -std=c11 -O2
LD := $(CC)
LDFLAGS :=
PROGS := example
.PHONY: all clean
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
example: out.o main.o
$(LD) $^ $(LDFLAGS) -o $@
接下来,out.h
:
#ifndef OUT_H
#define OUT_H 1
#include <stdio.h>
typedef enum {
out_char,
out_int,
out_double,
out_FILE,
out_set_fixed,
out_set_width,
out_set_decimals,
out_count
} out_type;
extern const char out_formats[out_count + 1];
extern int outf(FILE *, ...);
#define out(x...) outf(stdout, x)
#define err(x...) outf(stderr, x)
#define OUT(x) _Generic( (x), \
FILE *: out_formats + out_FILE, \
double: out_formats + out_double, \
int: out_formats + out_int, \
char: out_formats + out_char ), (x)
#define OUT_END ((const char *)0)
#define OUT_EOL "\n", ((const char *)0)
#define OUT_fixed(x) (out_formats + out_set_fixed), ((int)(x))
#define OUT_width(x) (out_formats + out_set_width), ((int)(x))
#define OUT_decimals(x) (out_formats + out_set_decimals), ((int)(x))
#endif /* OUT_H */
#ifndef OUT_H
#define OUT_H 1
#include <stdio.h>
typedef enum {
out_string = 1,
out_int,
out_double,
out_set_FILE,
out_set_fixed,
out_set_width,
out_set_decimals,
out_type_max
} out_type;
extern const char out_formats[out_type_max + 1];
extern int outf(FILE *, ...);
#define out(x...) outf(stdout, x)
#define err(x...) outf(stderr, x)
#define OUT(x) _Generic( (0,x), \
FILE *: out_formats + out_set_FILE, \
double: out_formats + out_double, \
int: out_formats + out_int, \
char *: out_formats + out_string ), (x)
#define OUT_END ((const char *)0)
#define OUT_EOL "\n", ((const char *)0)
#define OUT_fixed(x) (out_formats + out_set_fixed), ((int)(x))
#define OUT_width(x) (out_formats + out_set_width), ((int)(x))
#define OUT_decimals(x) (out_formats + out_set_decimals), ((int)(x))
#endif /* OUT_H */
请注意,上面缺少偶数OUT(“字符串文字”)
支持;这是一个非常简单的实现
最后,使用main.c
来显示使用上述方法的示例:
#include <stdlib.h>
#include "out.h"
int main(void)
{
double q = 1.0e6 / 7.0;
int x;
out("Hello, world!\n", OUT_END);
out("One seventh of a million is ", OUT_decimals(3), OUT(q), " = ", OUT_fixed(1), OUT(q), ".", OUT_EOL);
for (x = 1; x <= 9; x++)
out(OUT(stderr), OUT(x), " ", OUT_width(2), OUT(x*x), OUT_EOL);
return EXIT_SUCCESS;
}
下面是相应修改的实现,out.c
:
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include "out.h"
/* out_formats is a string consisting of ASCII NULs,
* i.e. an array of zero chars.
* We only check if a char pointer points to within out_formats,
* if it points to a zero char; otherwise, it's just a normal
* string we print as-is.
*/
const char out_formats[out_count + 1] = { 0 };
int outf(FILE *out, ...)
{
va_list args;
int fixed = 0;
int width = -1;
int decimals = -1;
if (!out)
return EINVAL;
va_start(args, out);
while (1) {
const char *const format = va_arg(args, const char *);
if (!format) {
va_end(args);
return 0;
}
if (*format) {
if (fputs(format, out) == EOF) {
va_end(args);
return 0;
}
} else
if (format >= out_formats && format < out_formats + sizeof out_formats) {
switch ((out_type)(format - out_formats)) {
case out_char:
if (fprintf(out, "%c", va_arg(args, int)) < 0) {
va_end(args);
return EIO;
}
break;
case out_int:
if (fprintf(out, "%*d", width, (int)va_arg(args, int)) < 0) {
va_end(args);
return EIO;
}
break;
case out_double:
if (fprintf(out, fixed ? "%*.*f" : "%*.*e", width, decimals, (float)va_arg(args, double)) < 0) {
va_end(args);
return EIO;
}
break;
case out_FILE:
out = va_arg(args, FILE *);
if (!out) {
va_end(args);
return EINVAL;
}
break;
case out_set_fixed:
fixed = !!va_arg(args, int);
break;
case out_set_width:
width = va_arg(args, int);
break;
case out_set_decimals:
decimals = va_arg(args, int);
break;
case out_count:
break;
}
}
}
}
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include "out.h"
const char out_formats[out_type_max + 1] = {
[ out_string ] = out_string,
[ out_int ] = out_int,
[ out_double ] = out_double,
[ out_set_FILE ] = out_set_FILE,
[ out_set_fixed ] = out_set_fixed,
[ out_set_width ] = out_set_width,
[ out_set_decimals ] = out_set_decimals,
};
int outf(FILE *stream, ...)
{
va_list args;
/* State (also, stream is included in state) */
int fixed = 0;
int width = -1;
int decimals = -1;
va_start(args, stream);
while (1) {
const char *const format = va_arg(args, const char *);
if (!format) {
va_end(args);
return 0;
}
if (*format > 0 && *format < out_type_max && format == out_formats + (size_t)(*format)) {
switch ((out_type)(*format)) {
case out_string:
{
const char *s = va_arg(args, char *);
if (s && *s) {
if (!stream) {
va_end(args);
return EINVAL;
}
if (fputs(s, stream) == EOF) {
va_end(args);
return EINVAL;
}
}
}
break;
case out_int:
if (!stream) {
va_end(args);
return EINVAL;
}
if (fprintf(stream, "%*d", width, (int)va_arg(args, int)) < 0) {
va_end(args);
return EIO;
}
break;
case out_double:
if (!stream) {
va_end(args);
return EINVAL;
}
if (fprintf(stream, fixed ? "%*.*f" : "%*.*e", width, decimals, va_arg(args, double)) < 0) {
va_end(args);
return EIO;
}
break;
case out_set_FILE:
stream = va_arg(args, FILE *);
if (!stream) {
va_end(args);
return EINVAL;
}
break;
case out_set_fixed:
fixed = !!va_arg(args, int);
break;
case out_set_width:
width = va_arg(args, int);
break;
case out_set_decimals:
decimals = va_arg(args, int);
break;
case out_type_max:
/* This is a bug. */
break;
}
} else
if (*format) {
if (!stream) {
va_end(args);
return EINVAL;
}
if (fputs(format, stream) == EOF) {
va_end(args);
return EIO;
}
}
}
}
#包括
#包括
#包括
#包括
#包括“out.h”
常量字符输出格式[输出类型最大+1]={
[out\u string]=out\u string,
[out\u int]=out\u int,
[out\u double]=out\u double,
[out\u set\u FILE]=out\u set\u FILE,
[out\u set\u fixed]=out\u set\u fixed,
[out\u set\u width]=out\u set\u width,
[out\u set\u decimals]=out\u set\u decimals,
};
int输出(文件*流,…)
{
va_列表参数;
/*状态(同样,流包含在状态中)*/
int固定=0;
整数宽度=-1;
整数小数=-1;
va_启动(参数、流);
而(1){
常量字符*常量格式=va_arg(args,常量字符*);
如果(!格式){
va_端(args);
返回0;
}
如果(*格式>0&&*格式#include <stdlib.h>
#include "out.h"
int main(void)
{
double q = 1.0e6 / 7.0;
int x;
out("Hello, world!\n", OUT_END);
out("One seventh of a million is ", OUT_decimals(3), OUT(q), " = ", OUT_fixed(1), OUT(q), ".", OUT_EOL);
for (x = 1; x <= 9; x++)
out(OUT(stderr), OUT(x), " ", OUT_width(2), OUT(x*x), OUT_EOL);
return EXIT_SUCCESS;
}
#ifndef OUT_H
#define OUT_H 1
#include <stdio.h>
typedef enum {
out_string = 1,
out_int,
out_double,
out_set_FILE,
out_set_fixed,
out_set_width,
out_set_decimals,
out_type_max
} out_type;
extern const char out_formats[out_type_max + 1];
extern int outf(FILE *, ...);
#define out(x...) outf(stdout, x)
#define err(x...) outf(stderr, x)
#define OUT(x) _Generic( (0,x), \
FILE *: out_formats + out_set_FILE, \
double: out_formats + out_double, \
int: out_formats + out_int, \
char *: out_formats + out_string ), (x)
#define OUT_END ((const char *)0)
#define OUT_EOL "\n", ((const char *)0)
#define OUT_fixed(x) (out_formats + out_set_fixed), ((int)(x))
#define OUT_width(x) (out_formats + out_set_width), ((int)(x))
#define OUT_decimals(x) (out_formats + out_set_decimals), ((int)(x))
#endif /* OUT_H */
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include "out.h"
const char out_formats[out_type_max + 1] = {
[ out_string ] = out_string,
[ out_int ] = out_int,
[ out_double ] = out_double,
[ out_set_FILE ] = out_set_FILE,
[ out_set_fixed ] = out_set_fixed,
[ out_set_width ] = out_set_width,
[ out_set_decimals ] = out_set_decimals,
};
int outf(FILE *stream, ...)
{
va_list args;
/* State (also, stream is included in state) */
int fixed = 0;
int width = -1;
int decimals = -1;
va_start(args, stream);
while (1) {
const char *const format = va_arg(args, const char *);
if (!format) {
va_end(args);
return 0;
}
if (*format > 0 && *format < out_type_max && format == out_formats + (size_t)(*format)) {
switch ((out_type)(*format)) {
case out_string:
{
const char *s = va_arg(args, char *);
if (s && *s) {
if (!stream) {
va_end(args);
return EINVAL;
}
if (fputs(s, stream) == EOF) {
va_end(args);
return EINVAL;
}
}
}
break;
case out_int:
if (!stream) {
va_end(args);
return EINVAL;
}
if (fprintf(stream, "%*d", width, (int)va_arg(args, int)) < 0) {
va_end(args);
return EIO;
}
break;
case out_double:
if (!stream) {
va_end(args);
return EINVAL;
}
if (fprintf(stream, fixed ? "%*.*f" : "%*.*e", width, decimals, va_arg(args, double)) < 0) {
va_end(args);
return EIO;
}
break;
case out_set_FILE:
stream = va_arg(args, FILE *);
if (!stream) {
va_end(args);
return EINVAL;
}
break;
case out_set_fixed:
fixed = !!va_arg(args, int);
break;
case out_set_width:
width = va_arg(args, int);
break;
case out_set_decimals:
decimals = va_arg(args, int);
break;
case out_type_max:
/* This is a bug. */
break;
}
} else
if (*format) {
if (!stream) {
va_end(args);
return EINVAL;
}
if (fputs(format, stream) == EOF) {
va_end(args);
return EIO;
}
}
}
}