Tag: 语言 律师

通过union未定义的行为进行const-casting?

与C ++不同,C没有const_cast概念。 也就是说,没有有效的方法将const限定指针转换为非限定指针: void const * p; void * q = p; // not good 首先:这个演员实际上是未定义的行为吗? 无论如何,GCC警告这一点。 要制作需要const-cast的“干净”代码(即我可以保证我不会改变内容,但我所拥有的只是一个可变指针),我看到了以下“转换”技巧: typedef union constcaster_ { void * mp; void const * cp; } constcaster; 用法: u.cp = p; q = u.mp; u.cp = p; q = u.mp; 。 通过这种联盟抛弃常量的C语言规则是什么? 我对C的了解只是非常不完整,但我听说C对联合访问比C ++要宽松得多,所以虽然我对这个结构有一种不好的感觉,但我想从标准中得到一个论证(C99我想,虽然如果在C11中这已经改变了,那么知道它会很好。

外部,内部和没有联系或为什么这不起作用?

根据C标准: 在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或function。 在一个翻译单元内,具有内部链接的标识符的每个声明表示相同的对象或function。 没有链接的标识符的每个声明表示唯一的实体。 在我的例子中,我们有三个单独的声明,每个标识符具有不同的链接。所以为什么这不起作用? static int a; //a_Internal int main(void) { int a; //a_Local { extern int a; //a_External } return 0; } 错误: 在函数’main’中:第9行:错误:变量先前声明’static’relayclared’extern’ 为什么编译器坚持要重新声明我而不是尝试访问另一个文件中的外部对象? 有效的C ++示例供参考: static void f(); static int i = 0; // #1 void g() { extern void f(); // internal linkage int i; // #2 i has no […]

C运算符+ =序列点?

这是定义的行为吗? *p += *p–; 并且,如果是,它是否等于{ p[0] += p[0]; –p; } { p[0] += p[0]; –p; } { p[0] += p[0]; –p; }或{ p[-1] = p[0]; –p; } { p[-1] = p[0]; –p; } { p[-1] = p[0]; –p; } ? 我猜测是否定义取决于+=是否具有隐式序列点,如果有,我的猜测是第二个块应该是正确的。 编辑:我认为这不是建议问题的重复,因为主要问题是什么是序列点以及如何影响行为。 在我的情况下,我清楚地知道序列点是什么,问题是关于+=运算符是否具有隐式序列点。

为什么编译器会假设这些看似相等的指针有所不同?

看起来GCC有一些优化认为来自不同翻译单元的两个指针永远不会相同,即使它们实际上是相同的。 码: main.c中 #include #include int a __attribute__((section(“test”))); extern int b; void check(int cond) { puts(cond ? “TRUE” : “FALSE”); } int main() { int * p = &a + 1; check( (p == &b) == ((uintptr_t)p == (uintptr_t)&b) ); check(p == &b); check((uintptr_t)p == (uintptr_t)&b); return 0; } 公元前 int b __attribute__((section(“test”))); 如果我用-O0编译它,它会打印出来 TRUE […]

多维数组的别名

众所周知,2D数组是一个数组数组,标准要求它是一个连续分配的非空对象集 (6.2.5类型§20) – 这里的对象是一维数组。 众所周知,对于所有常见的实现,对于T arr2d[X][Y] ,以下等式是正确的,其中T是一个类型,X和Y的积分常数: (char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T) 以上让我们认为可以允许对两个相同大小的二维数组和一维数组进行别名,或者甚至是另一个总大小相同的二维数组: 例如,以下程序编译并运行时没有警告,并给出预期输出: #include int main() { int i, j, k=0; int arr2d[3][4]; // array of 3 array of 4 ints int *arr1 = &arr2d[0][0]; // pointer to first element of an […]

你可以将“指向函数指针的指针”转换为void *

灵感来自对我的回答的评论。 这一系列步骤在C标准(C11)中是否合法? 创建一个函数指针数组 获取指向第一个条目的指针并将该指针转换为函数指针 void* 对该void*执行指针算术void* 将其强制转换为指向函数指针的指针并取消引用它。 或者相当于代码: void foo(void) { … } void bar(void) { … } typedef void (*voidfunc)(void); voidfunc array[] = {foo, bar}; // Step 1 void *ptr1 = array; // Step 2 void *ptr2 = (char*)ptr1 + sizeof(voidfunc); // Step 3 voidfunc bar_ptr = *(voidfunc*)ptr2; // Step 4 我认为这是允许的,因为实际的函数指针只能通过正确的类型指针访问。 但Andrew Henle指出, […]

为什么union *和struct *之间可能存在差异?

C标准要求所有指向union的指针具有相同的表示和对齐要求。 它对struct s的所有指针都强制要求。 因此,我的问题: 为什么标准不强制指向union的指针具有与struct s指针相同的表示和对齐要求? (我非常感谢一个利用这个实现的实现的例子。) 或者我只是错过了相关的文字? 标准草案n1570(C11最终草案)的相关引用: 6.2.5类型§28 指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求。 48)类似地,指向兼容类型的合格或非限定版本的指针应具有相同的表示和对齐要求。 所有指向结构类型的指针都应具有相同的表示和对齐要求。 所有指向union类型的指针都应具有相同的表示和对齐要求。 指向其他类型的指针不需要具有相同的表示或对齐要求。

在动态bool数组上使用memset是否定义明确?

在严格别名方面,这段代码是明确定义的行为吗? _Bool* array = malloc(n); memset(array, 0xFF, n); _Bool x = array[0]; 有效类型的规则有memcpy和memmove特殊情况(C176.5§6),但不适用于memset 。 我的看法是有效类型变为unsigned char 。 因为memset的第二个参数需要转换为unsigned char (C17 7.24.6.1),并且由于有效类型的规则,(C176.5§6): …或者被复制为字符类型数组,然后该访问的修改对象的有效类型以及不修改该值的后续访问是从中复制值的对象的有效类型,如果它有一个。 问题1:在memset调用之后, array存储的数据的有效类型是什么? 问题2: array[0]访问是否违反了严格的别名? 由于_Bool不是严格别名规则中排除的类型(与字符类型不同)。

memcpy可以用于打字吗?

这是C11标准的引用: 6.5表达式 … 6访问其存储值的对象的有效类型是对象的声明类型(如果有)。 如果通过具有非字符类型的类型的左值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。 如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。 7对象的存储值只能由具有以下类型之一的左值表达式访问: – 与对象的有效类型兼容的类型, – 与对象的有效类型兼容的类型的限定版本, – 对应于对象的有效类型的有符号或无符号类型, – 对应于对象有效类型的限定版本的有符号或无符号类型, – 聚合或联合类型,其成员中包含上述类型之一(包括递归地,子聚合或包含联合的成员),或者 – 一个字符类型。 这是否意味着memcpy不能以这种方式用于类型惩罚: double d = 1234.5678; uint64_t bits; memcpy(&bits, &d, sizeof bits); printf(“the representation of %g is %08″PRIX64″\n”, d, bits); 为什么它不会给出相同的输出: union { double d; uint64_t i; } u; ud = 1234.5678; printf(“the representation of %g […]

C中的此代码是否属于未定义行为类别?

a是一个数组, foo是一个函数, i是一个int 。 a[++i] = foo(a[i-1], a[i]); 上面的代码会有未定义的行为吗? 数组索引++i , i-1和i保证在数组范围内。