Questions tagged «c»

C是用于系统编程(OS和嵌入式),库,游戏和跨平台的通用编程语言。该标记应与ISO 9899标准(除非另有说明,最新版本9899:2018中定义的有关C语言的一般问题)一起使用-还要使用c89,c99,c11等标记特定于版本的请求。C与C ++截然不同,在没有合理理由的情况下,不应将其与C ++标记结合使用。

3
从函数返回唯一的空指针
要从void *CI中的函数获取a ,将执行以下操作(非常基本的示例): void *get_ptr(size_t size) { void *ptr = malloc(size); return ptr; } 使用时如何获得相同的结果std::unique_ptr<>?
11 c++  c  unique-ptr 

2
IBM示例代码,不可重入函数在我的系统中不起作用
我正在研究编程的重入性。在IBM的这个站点上(确实不错)。我建立了一个代码,复制到下面。这是在网站上滚动的第一个代码。 该代码尝试通过打印在“危险上下文”中不断变化的两个值来显示涉及在文本程序的非线性开发中共享访问变量的问题(异步性)。 #include <signal.h> #include <stdio.h> struct two_int { int a, b; } data; void signal_handler(int signum){ printf ("%d, %d\n", data.a, data.b); alarm (1); } int main (void){ static struct two_int zeros = { 0, 0 }, ones = { 1, 1 }; signal (SIGALRM, signal_handler); data = zeros; alarm …
11 c  gcc  signals  x86-64  data-race 

1
GCC实施的尖括号包含。为什么必须如下所述?
本文档在其2.6计算的包括部分中具有以下段落: 如果该行扩展到以<令牌开头并包括>令牌的令牌流,则<和第一个>之间的令牌将合并以形成要包含的文件名。令牌之间的任何空格都减少为一个空格;那么将保留初始<之后的任何空格,但忽略闭合>之前的结尾空格。CPP根据尖括号包含的规则搜索文件。 我知道这是实现定义的,但是为什么GCC必须采用这种方式?我指的是上面突出显示的句子。 编辑 我刚刚注意到,上面引用的第三段之前的内容如下: 定义宏时必须小心。#define保存令牌,而不是文本。预处理器无法知道该宏将用作的参数#include,因此它会生成普通标记,而不是标头名称。如果您使用的双引号包含与字符串常量足够接近,则这不太可能引起问题。 但是,如果使用尖括号,则可能会遇到麻烦。 有谁知道这里指出了什么麻烦?
10 c++  c  gcc  language-lawyer 

1
为何编译器坚持在此处使用被调用者保存的寄存器?
考虑下面的C代码: void foo(void); long bar(long x) { foo(); return x; } 当我在GCC 9.3上使用-O3或编译它时-Os,得到以下信息: bar: push r12 mov r12, rdi call foo mov rax, r12 pop r12 ret clang的输出是相同的,除了选择rbx而不是r12作为被调用者保存的寄存器。 但是,我希望/希望看到看起来像这样的程序集: bar: push rdi call foo pop rax ret 用英语,这就是我所看到的: 将已保存被调用者的寄存器的旧值推入堆栈 移动x到该被调用方保存寄存器 呼叫 foo 移动x从被调用者被保存的寄存器到返回值寄存器 弹出堆栈以恢复被调用方保存的寄存器的旧值 为什么要弄乱所有保存在被调用方中的寄存器?为什么不这样做呢?它看起来更短,更简单,并且可能更快: 推x入栈 呼叫 foo x从堆栈弹出到返回值寄存器 我的大会错了吗?它比以多余的寄存器搞乱效率低吗?如果对这两个问题的回答都是“否”,那么为什么GCC或clang都不这样做呢? …
10 c  gcc  assembly  clang  x86-64 

3
不同编译器中C ++和C之间无符号位域整数表达式的截断不一致
编辑2: 当以前驻留在C ++源文件中但完全移入C文件的函数开始返回不正确的结果时,我正在调试一个奇怪的测试失败。下面的MVE允许重现GCC问题。但是,当我一时兴起,用Clang(后来又用VS)编译示例时,得到了不同的结果!我无法弄清楚是将其视为编译器之一中的错误,还是C或C ++标准允许的未定义结果的体现。奇怪的是,没有一个编译器给我有关该表达式的任何警告。 罪魁祸首是这样的表达: ctl.b.p52 << 12; 在这里,p52键入为uint64_t;它也是工会的一部分(见control_t下文)。移位操作不会丢失任何数据,因为结果仍然适合64位。但是,如果我使用C编译器,那么GCC决定将结果截断为52位!使用C ++编译器,将保留所有64位结果。 为了说明这一点,下面的示例程序用相同的主体编译了两个函数,然后比较了它们的结果。c_behavior()放在C源文件和cpp_behavior()C ++文件中,并main()进行比较。 带有示例代码的存储库:https : //github.com/grigory-rechistov/c-cpp-bitfields 标头common.h定义64位宽位域和整数的并集,并声明两个函数: #ifndef COMMON_H #define COMMON_H #include <stdint.h> typedef union control { uint64_t q; struct { uint64_t a: 1; uint64_t b: 1; uint64_t c: 1; uint64_t d: 1; uint64_t e: 1; uint64_t f: 1; uint64_t g: …

1
是否将设置为CHAR_MAX的char值保证可以绕回CHAR_MIN?
我的代码: #include <stdio.h> #include <limits.h> int main() { char c = CHAR_MAX; c += 1; printf("CHAR_MIN=%d CHAR_MAX=%d c=%d (%c)\n", CHAR_MIN, CHAR_MAX, c, c); } 输出: CHAR_MIN=-128 CHAR_MAX=127 c=-128 () 我们看到,当我们将char变量设置为递增时CHAR_MAX,它会绕到CHAR_MIN。这种行为得到保证吗?还是将是未定义的行为或实现特定的行为?C99标准对此有何说法? [注意:当给char或C 大于CHAR_MAX(127)的值时会发生什么?为什么char c = 129会转换为-127?之所以没有解决这个问题,是因为他们谈论分配超出范围的值,而不是将值递增到超出范围的值。]


1
C11原子获取/发布和x86_64缺乏加载/存储一致性?
我在C11标准的5.1.2.4节中苦苦挣扎,尤其是Release / Acquire的语义。我注意到https://preshing.com/20120913/acquire-and-release-semantics/(以及其他)指出: ...释放语义可防止以程序顺序在写释放之前进行任何读或写操作,从而对写释放进行内存重新排序。 因此,对于以下情况: typedef struct test_struct { _Atomic(bool) ready ; int v1 ; int v2 ; } test_struct_t ; extern void test_init(test_struct_t* ts, int v1, int v2) { ts->v1 = v1 ; ts->v2 = v2 ; atomic_store_explicit(&ts->ready, false, memory_order_release) ; } extern int test_thread_1(test_struct_t* ts, int v2) { …

4
为什么要从main()返回NULL?
我有时会看到在C和C ++程序中NULL用作返回值的编码器,main()例如: #include <stdio.h> int main() { printf("HelloWorld!"); return NULL; } 当我用gcc编译此代码时,得到以下警告: 警告:return从指针转换为整数而不进行强制转换[-Wint-conversion] 这是合理的,因为宏NULL应扩展为,(void*) 0并且main的返回值应为类型int。 当我制作一个简短的C ++程序时: #include <iostream> using namespace std; int main() { cout << "HelloWorld!"; return NULL; } 并使用g ++进行编译,我得到了等效的警告: 警告:从NULL转换为非指针类型'int'[-Wconversion-null] 但是,为什么当警告NULL发生main()时将它们用作返回值呢?这只是不好的编码风格吗? 尽管有警告,仍要使用NULL而不是将其0用作返回值的原因是什么main()? 它是否是实现定义的,是否合适?如果是,为什么任何实现都希望返回指针值?
10 c++  c  null  return  return-value 

2
L2 HW预取器真的有用吗?
我在Whiskey Lake i7-8565U上,分析性能计数器和复制512 KiB数据的时间(是L2缓存大小的两倍),并且对L2 HW预取器的工作遇到了一些误解。 在英特尔手册第4卷MSR中,有MSR 0x1A4的位0用于控制L2硬件预取器(禁用1)。 考虑以下基准: memcopy.h: void *avx_memcpy_forward_lsls(void *restrict, const void *restrict, size_t); memcopy.S: avx_memcpy_forward_lsls: shr rdx, 0x3 xor rcx, rcx avx_memcpy_forward_loop_lsls: vmovdqa ymm0, [rsi + 8*rcx] vmovdqa [rdi + rcx*8], ymm0 vmovdqa ymm1, [rsi + 8*rcx + 0x20] vmovdqa [rdi + rcx*8 + 0x20], ymm1 add …

1
升级到macOS Mojave后,MATLAB不再卸载MEX文件
在MATLAB中,clear mex从内存中卸载所有MEX文件(除非它们已被锁定)。在macOS的早期版本下,我只需发出clear mex命令即可重新编译MEX文件并运行修改后的版本,而无需重新启动MATLAB 。在莫哈韦沙漠下,这不再可能。 例如,使用以下简单的MEX文件(get_data_pointer.c): #include "mex.h" void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); *(uint64_t*)mxGetData(plhs[0]) = (uint64_t)mxGetData(prhs[0]); } 我们可以创建MEX文件并将其加载到内存中 mex get_data_pointer.c get_data_pointer(0) 为了清除它, clear mex [~,mexfiles] = inmem version -modules inmem确实返回了一个空单元格数组,指示未在内存中加载任何MEX文件,但是version -modules(未记录,根据此答案)仍显示/Users/cris/matlab/get_data_pointer.mexmaci64在其输出中。更改MEX文件的源代码并重新编译表明,确实从未重新加载MEX文件,旧版本仍在运行,直到有人退出MATLAB。 我在macOS Mojave的MATLAB R2017a上看到了这一点。在High Sierra下使用相同的MATLAB版本从来没有问题。 如何强制MATLAB在不重新启动的情况下卸载MEX文件?

5
动态链接-Linux与。视窗
在Windows下,当我在MSVC的DLL项目中编译C / C ++代码时,我得到2个文件: MyDll.dll MyDll.lib 据我了解,MyDll.lib其中包含某种指示符表,用于指示dll中的函数位置。使用此dll时(例如在exe文件中),MyDll.lib在链接期间会嵌入到exe文件中,因此在运行时它“知道”函数的位置MyDll.dll并可以使用它们。 但是,如果我在Linux下编译相同的代码,我只会得到一个MySo.so不带 文件的文件MySo.a(相当于libLinux中的文件),那么MySo.so如果在链接过程中未嵌入任何内容,Linux下的可执行文件如何知道函数的位置?

4
字符数组应如何用作字符串?
我知道C中的字符串只是字符数组。因此,我尝试了以下代码,但给出了奇怪的结果,例如垃圾输出或程序崩溃: #include <stdio.h> int main (void) { char str [5] = "hello"; puts(str); } 为什么不起作用? 它可以用干净地编译gcc -std=c17 -pedantic-errors -Wall -Wextra。 注意:对于在声明字符串时未能为NUL终止符分配空间而引起的问题,本帖子旨在用作规范的FAQ。


2
如果未定义的C ++行为符合C定义的行为会发生什么?
我有一个*.cpp使用C ++编译的文件(不是C编译器)。包含函数依赖于强制转换(请参见最后一行),该强制转换似乎是在C中定义的(如果我错了,请更正!),但对于这种特殊类型,则不在C ++中定义。 [...] C++ code [...] struct sockaddr_in sa = {0}; int sockfd = ...; sa.sin_family = AF_INET; sa.sin_port = htons(port); bind(sockfd, (struct sockaddr *)&sa, sizeof sa); [...] C++ code [...] 由于我将其编译为C ++文件,因此这是现在定义的还是未定义的行为?还是我需要将其移动到*.c文件中以使其定义为行为?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.