Tag: 语言律师

`long`保证与`size_t`一样宽

当寻找unsigned long证据足以容纳size_t以便成为printf参数时,我遇到了两个事实(oid)s。 首先,这个答案表明long确实不足以保证size_t足够大。 另一方面,我看到这个答案建议在前C99中使用printf(“%lu”, (unsigned long)x) , x是size_t 。 所以问题是你可以假设或者你保证在C99之前持有size_t long足够long 。 另一个问题是,是否有任何保证size_t适合任何其他标准化整数类型(除了明显的例外,如ssize_t , ptrdiff_t等)。

枚举是否是位域实现定义的类型?

我试图更好地理解C99标准,但现在我对使用枚举作为结构中的位域以及它们被视为int还是实现定义类型感到困惑。 在查看C99的最终草案时,我找到了6.7.2.1段。 4 位字段的类型应为_Bool , signed int , unsigned int或其他实现定义类型的限定或非限定版本。 和6.7.2.2段。 4 每个枚举类型应与char ,有符号整数类型或无符号整数类型兼容。 类型的选择是实现定义的,但应能够表示枚举的所有成员的值。 … 所以我尝试使用这个简单的源代码 enum e { E0, E1 }; struct s { enum e bitfield : 4; }; 我可以用gcc-5.0和clang-3.5使用-std=c99 -Wall -Wextra -pedantic编译这个没有警告但是我用gcc-4.8得到以下警告 warning: type of bit-field ‘bitfield’ is a GCC extension 这里开始混乱。 枚举是否将位域视为int或实现定义的类型? 这是GCC-4.8中的错误还是他们改变了对标准的解释? 与其他C99编译器一起使用是否安全?

为什么_Alignof在关于将数组转换为指针的规则中缺失?

C 2011(草案N1570)6.3.2.1 3说: 除非它是sizeof运算符, _Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则具有类型”数组类型 ”的表达式将转换为表达式输入”指向类型’的指针,指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。 C 2018 6.3.2.1 3说: 除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“array of type ”的表达式转换为类型为“指向类型的指针”的表达式指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。 为什么后者缺少_Alignof ? C 2018 Foreward 7说: 此版本没有重大变化,只有技术更正和说明。 这意味着从数组转换规则中豁免_Alignof有一些不正确之处,导致它被删除。 但是,应该可以将_Alignof应用于数组,如C 2018 6.5.3.4 3所述: _Alignof运算符产生其操作数类型的对齐要求。 不评估操作数,结果是整数常量。 应用于数组类型时,结果是元素类型的对齐要求。

无符号整数递增会导致未定义的定义行为吗?

在64位读取32位无符号乘法后导致未定义的行为? 问题在StackOverflow上,我开始思考根据C99标准,对小型无符号类型的典型算术运算是否会导致未定义的行为。 例如,请使用以下代码: #include … unsigned char x = UCHAR_MAX; unsigned char y = x + 1; x变量初始化为unsigned char数据类型的最大幅度。 下一行是问题:值x + 1大于UCHAR_MAX ,不能存储在unsigned char变量y 。 我相信以下是实际发生的事情。 变量x首先被提升为数据类型int (第6.3.1.1/2节),然后x + 1被计算为数据类型int 。 假设存在INT_MAX和UCHAR_MAX相同的实现 – x + 1将导致有符号整数溢出。 这是否意味着递增变量x ,尽管是无符号整数类型,由于可能的有符号整数溢出会导致未定义的行为?

为什么“从’X *’转换为’Y’会失去精度”这是一个很难的错误,什么是遗留代码的合适修复

1.为什么? 像这样的代码过去常常起作用,它应该是什么意思。 编译器是否允许 (通过规范)使其成为错误? 我知道它正在失去精确度,我会很高兴收到警告。 但它仍然有一个明确定义的语义(至少对于未定义的缩小版本定义)并且用户可能想要这样做。 2.解决方法 我有遗留代码,我不想重构太多,因为它相当棘手并且已经调试过。 它做了两件事: 有时在指针变量中存储整数。 如果代码之前存储了一个整数,则代码仅将指针强制转换为整数。 因此,当演员阵容缩小时,溢出在现实中永远不会发生。 代码经过测试和运行。 当存储整数时,它总是适合普通的旧无符号,因此改变类型不被认为是一个好主意并且指针传递相当多,所以改变它的类型将有点侵入性。 使用地址作为哈希值。 一个相当常见的事情。 哈希表对于扩展类型没有任何意义。 代码使用普通的unsigned作为哈希值,但请注意,更常见的size_t类型仍可能生成错误 ,因为无法保证sizeof(size_t) > = sizeof(void *) 。 在具有分段内存和远指针的平台上, size_t只需要覆盖偏移部分。 那么最具侵入性的合适解决方法是什么? 已知代码在使用不会产生此错误的编译器编译时工作,所以我真的想要进行操作,而不是更改它。 笔记: void *x; int y; union U { void *p; int i; } u; *(int*)&x和up = x, ui 不等于(int)x ,与(void *)y 不相反。 在大端架构上,前两个将返回较低地址上的字节,而后一个将在低位字节上工作,这些字节可能位于较高地址上。 *(int*)&x和up = x, ui都是严格的别名冲突, […]

当一个`int`处于最大值并使用postfix ++进行测试时,代码是否定义良好?

示例未定义行为的示例是整数溢出的行为。 C11dr§3.4.33 int overflow是未定义的行为,但这是否适用于存在循环的以下内容,并且不使用现在超出范围的i的副作用? 特别是,这个Postfix增量规范有帮助吗? …在更新操作数的存储值的副作用之前,对结果的值计算进行排序。 ……§6.5.2.42 使用启用良好的C11编译时没有警告 #include #include int main(void) { // Specified behavior when `i` has the value `INT_MAX`? for (int i = INT_MAX – 2; i++ < INT_MAX;) { printf("%d\n", i); } puts("Done"); return 0; } 样本输出 2147483646 2147483647 Done 当然可以重写代码以避免下面的这种窘境。 仍然,寻找有关上述的确认。 (我认为是UB。) INT_MIN和i–存在类似的问题。 for (int i = INT_MAX – 2; […]

调用printf有多余的参数未定义的行为?

我想知道这是否会产生未定义的行为: printf(“Test %d %s”, 123, “abc”, “def”, “ghi”); 格式字符串后面的前两个参数匹配格式字符串,所以这些都可以; 但第3和第4个参数过多,因为没有更多相应的格式说明符。 IMHO printf()应该简单地忽略这些多余的参数,并且应该没有UB。 它是否正确?

如果您知道在到达有效区域的末尾之前找到该字符,那么调用长度过长的memchr是否合法?

在C11和C ++ 11 1中是否有以下定义的行为? bool has4() { char buf[10] = {0, 1, 2, 4}; return memchr(buf, 4, 20); } 在这里,我们通过一个太长的长度memchr 。 数组有10个元素,但是我们传递了20.但是,我们搜索的元素总是在结束之前找到。 我很清楚这是否合法。 如果允许这样做,则会限制实现的灵活性,因为实现不能依赖于大小是可访问存储器区域大小的有效指示,因此必须小心读取超出找到的元素。 一个例子是希望从传入指针开始执行16字节SIMD加载然后并行检查所有16个字节的实现。 如果用户传递的长度为16,则只有在需要访问整个长度时才会安全。 否则(如果上面的代码是合法的),实现必须避免对目标元素之外的元素进行潜在的error handling,例如通过对齐加载(可能很昂贵)或检查指针是否接近保护边界的末尾 。 1这是一个罕见的问题,我猜C和C ++的标记是有效的:据我所知,C ++标准只是在行为方面直接推迟到C标准,但是如果不是这样的话我想知道。

以下代码可以用于指向不同事物的指针

我有一段记忆,我正在“守卫”,定义为 typedef unsigned char byte; byte * guardArea; size_t guardSize; byte * guardArea = getGuardArea(); size_t guardSize = getGuardSize(); 为此目的可接受的实现是: size_t glGuardSize = 1024; /* protect an area of 1kb */ byte * getGuardArea() { return malloc( glGuardSize ); } size_t getGuardSize() { return glGuardSize; } 以下代码段可以为任何指针(来自不同的malloc,来自堆栈等)返回true吗? if ( ptr >= guardArea && ptr < […]

如何在C编译器内部处理数组和指针类型? (int * a;与int a ;)

我需要一位拥有权威资源的语言律师。 看看下面的测试程序,它在gcc下干净地编译: #include void foo(int *a) { a[98] = 0xFEADFACE; } void bar(int b[]) { *(b+498) = 0xFEADFACE; } int main(int argc, char **argv) { int a[100], b[500], *a_p; *(a+99) = 0xDEADBEEF; *(b+499) = *(a+99); foo(a); bar(b); printf(“a[98] == %X\na[99] == %X\n”, a[98], a[99]); printf(“b[498] == %X\nb[499] == %X\n”, b[498], b[499]); a_p = a+98; *a_p […]