为了拥有干净的代码,使用一些 OO 概念可能很有用,即使在 C 中也是如此。
我经常编写由一对 .h 和 .c 文件组成的模块。问题是模块的用户必须小心,因为 C 中不存在私有成员。使用 pimpl 习惯用法或抽象数据类型是可以的,但它添加了一些代码和/或文件,并且需要较重的代码。当我不需要访问器时,我讨厌使用访问器。
这里有一个想法,它提供了一种方法,让编译器抱怨对“私有”成员的无效访问,只需一些额外的代码。这个想法是定义两次相同的结构,但为模块的用户添加一些额外的“const”。
当然,通过演员阵容仍然可以在“私人”成员中写作。但重点只是为了避免模块用户的错误,而不是安全地保护内存。
/*** 2DPoint.h module interface ***/
#ifndef H_2D_POINT
#define H_2D_POINT
/* 2D_POINT_IMPL need to be defined in implementation files before #include */
#ifdef 2D_POINT_IMPL
#define _cst_
#else
#define _cst_ const
#endif
typedef struct 2DPoint
{
/* public members: read and write for user */
int x;
/* private members: read only for user */
_cst_ int y;
} 2DPoint;
2DPoint *new_2dPoint(void);
void delete_2dPoint(2DPoint **pt);
void set_y(2DPoint *pt, int newVal);
/*** 2dPoint.c module implementation ***/
#define 2D_POINT_IMPL
#include "2dPoint.h"
#include <stdlib.h>
#include <string.h>
2DPoint *new_2dPoint(void)
{
2DPoint *pt = malloc(sizeof(2DPoint));
pt->x = 42;
pt->y = 666;
return pt;
}
void delete_2dPoint(2DPoint **pt)
{
free(*pt);
*pt = NULL;
}
void set_y(2DPoint *pt, int newVal)
{
pt->y = newVal;
}
#endif /* H_2D_POINT */
/*** main.c user's file ***/
#include "2dPoint.h"
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
2DPoint *pt = new_2dPoint();
pt->x = 10; /* ok */
pt->y = 20; /* Invalid access, y is "private" */
set_y(pt, 30); /* accessor needed */
printf("pt.x = %d, pt.y = %d\n", pt->x, pt->y); /* no accessor needed for reading "private" members */
delete_2dPoint(&pt);
return EXIT_SUCCESS;
}
现在,问题是:这个技巧符合 C 标准吗?
它与 GCC 一起工作得很好,并且编译器不会抱怨任何事情,即使有一些严格的标志,但我如何确定这真的没问题?
这几乎肯定是未定义的行为。
写入/修改声明为的对象const
被禁止,这样做会导致 UB。此外,您采取的方法重新声明struct 2DPoint
作为两种技术上不同的类型,这也是不允许的。
请注意,这(通常是未定义的行为)并不意味着它“肯定不会工作”或“它必须崩溃”。其实我觉得还蛮逻辑上它有效,因为如果一个人明智地阅读来源,他可以很容易地找出它的目的是什么以及为什么它可能被认为是正确的。然而,编译器并不智能——充其量,它是一个有限自动机,不知道代码是什么supposed去做;它只(或多或少)遵守语法的句法和语义规则。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)