I am trying to initialize struct sigaction (from sigaction.h) using C++20 designated initializers, but there are compiler errors. As this is part of a larger program, I created a short example:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void onSIGINT(int signal, siginfo_t *siginfo, void *context) {
printf("Caught signal\n");
}
int main(int argc, char** argv) {
struct sigaction act = {
.sa_sigaction = onSIGINT,
.sa_flags = SA_SIGINFO
};
if(sigaction(SIGINT, &act, nullptr) != 0) {
fprintf(stderr, "Failed to listen for SIGINT\n");
return 1;
}
printf("Waiting for signal...\n");
pause();
printf("Exit\n");
return 0;
}
According to https://gcc.gnu.org/projects/cxx-status.html#cxx20 designated initializers are available in gcc8. Running g++ (v8.3.0 on Debian buster) with -std=c++2a gives the following error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:9: error: expected primary-expression before ‘.’ token
.sa_sigaction = onSIGINT,
^
main.cpp:12:9: error: either all initializer clauses should be designated or none of them should be
.sa_flags = SA_SIGINFO
^
Initializing only sa_flags compiles successfully, initializing only sa_sigaction fails to compile (only first error).
I also tried to initialize __sigaction_handler directly (no using the define to access the union member):
struct sigaction act = {
.__sigaction_handler = { .sa_sigaction = onSIGINT },
.sa_flags = SA_SIGINFO
};
That produces a similar error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:12:34: error: expected primary-expression before ‘.’ token
.__sigaction_handler = { .sa_sigaction = onSIGINT },
^
I suppose I am doing something wrong about the union inside the struct, but I can't figure out what.
I am aware that I could achieve roughly the same by zeroing the memory of the struct and then setting callback and flags, but thats not the point.
The problem is that sa_sigaction is a macro, defined to __sigaction_handler.sa_sigaction. This means that your code expands to .__sigaction_handler.sa_sigaction = onSIGINT; this is valid C, where a named member initializer is allowed to have a complex structure, but it is not valid in C++20.
You can see that by #undefing it:
#undef sa_sigaction
.__sigaction_handler = { .sa_sigaction = onSIGINT },
However this is non-portable (undefining a standard library macro, not to mention using a double-underscore prefixed member), so I would recommend against it.
Related
I want to use std::compare_exchange_strong for some std::atomic<int>
For compilation reasons (int &) I am forced to introduce int _OLD_VALUE = OLD_VALUE.
Is there a more elegant way to achieve this?
Here is my example
#include <atomic>
#include <stdio.h>
#define OLD_VALUE 16
#define NEW_VALUE 744
#define OTHER_VALUE 80
int main(int argc, char **argv)
{
std::atomic<int> i(OTHER_VALUE);
int _OLD_VALUE = OLD_VALUE;
bool status = i.compare_exchange_strong(_OLD_VALUE,NEW_VALUE);
// bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
}
And here is the compilation error when I use the commented version:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:65: error: cannot bind non-const lvalue reference of type ‘std::__atomic_base<int>::__int_type& {aka int&}’ to an rvalue of type ‘int’
bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
^
In file included from /usr/include/c++/7/atomic:41:0,
from main.cpp:1:
/usr/include/c++/7/bits/atomic_base.h:496:7: note: initializing argument 1 of ‘bool std::__atomic_base<_IntTp>::compare_exchange_strong(std::__atomic_base<_IntTp>::__int_type&, std::__atomic_base<_IntTp>::__int_type, std::memory_order) [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]’
compare_exchange_strong(__int_type& __i1, __int_type __i2,
^~~~~~~~~~~~~~~~~~~~~~~
No. The reason being is that the previous value of the variable is exchanged so the expected value is overwritten if the compare mismatches.
To see what's going on under the hood, look at the GCC built-ins:
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
You will note there is a __atomic_exchange_n in the builtins for GCC (Linux) but that simply provides an exchange as opposed to a compare-and-swap. The Windows equivalent is InterlockedExchange : https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange
For the sake of readability I would avoid using capitals in variable names and avoid leading underscores:
int oldValue = OLD_VALUE;
The simplest way (and I suppose the only way) to achieve this is to just write simple wrapper:
bool cas_strong(std::atomic<int>& a, int cmp, int exc) {
return a.compare_exchange_strong(cmp, exc);
}
compare_exchange_strong expects an int& to store the current value found in i. Here, you provide indirectly 16 (that is what your macro OLD_VALUE is replaced with at pre-processing), which is an integer compile-time constant, a.k.a. constexpr int&. This is not compatible with int&.
To provide an int&, you should better keep an int near your call of compare_exchange_strong:
std::atomic<int> i(OTHER_VALUE);
int old_value = OLD_VALUE;
bool status = i.compare_exchange_strong(old_value, NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
Also, more generally, it is clearly more powerful if you used static constants instead of macros here.
More on this in this other question: What is the difference between a macro and a const in C++?
Don't use macros to define the values:
#include <atomic>
#include <stdio.h>
int OLD_VALUE 16
int NEW_VALUE 744
int OTHER_VALUE 80
int main(int argc, char **argv)
{
std::atomic<int> i(OTHER_VALUE);
bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
}
I am trying to launch a function threaded using launch::async. However, I noticed that this doesn't work when passing struct elements as parameter:
The code
#include <future>
#include <vector>
#include <thread>
struct example { int ten; };
void threadFunction(int number, std::string hi) {
printf("%s Your number is %d\n", hi.c_str(), number + 1);
}
int main() {
example ex;
ex.ten = 9;
std::string someString = "Hi there!";
std::vector< std::future< void > > threads(5);
for (uint16_t s = 0; s < 5; s += 1) {
threads[s] = async(std::launch::async,
[ex.ten,
someString] {
threadFunction(ex.ten, someString);
});
}
}
gives the following errors:
file.cpp: In function ‘int main()’:
file.cpp:25:39: error: expected ‘,’ before ‘.’ token
[ex.ten,
^
file.cpp:25:39: error: expected identifier before ‘.’ token
file.cpp:25:43: error: expected ‘]’ before ‘,’ token
[ex.ten,
^
file.cpp: In lambda function:
file.cpp:25:43: error: expected ‘{’ before ‘,’ token
file.cpp: In function ‘int main()’:
file.cpp:26:46: error: expected ‘)’ before ‘]’ token
someString] {
^
file.cpp:28:8: error: expected primary-expression before ‘)’ token
});
When replacing ex.ten with some other variable ten it does work.
So my questions are:
1. Why does launch::async not work with struct elements?
2. Is there a way to do it in a more elegant way than to make a variable for each element in the struct and pass those variables instead? (such as int ten = ex.ten; etc)
You can't pass single struct field that way into lambda in C++. The error you get is not connected to std::launch or communicating between threads. What you can do instead is:
C++11 - copy field into local variable and capture that variable:
auto ten = ex.ten;
threads[s] = async(std::launch::async,
[ten,
someString] {
threadFunction(ten, someString);})
C++14 and later - initialize variable in capture list:
threads[s] = async(std::launch::async,
[ten = ex.ten,
someString] {threadFunction(ten, someString);})
What you are trying to do is to capture a field in the struct in lambda. This is not possible, you can only capture the whole struct.
It has nothing to do with std::launch, it's a basic property of lambda closure.
In C++14, you can have captures with initializers, which might be what you want:
auto lam = [ten = ex.ten]...
I have a question regarding to the code snippet appended below. Anyway I ran the snippet on ideone.com and got two different results
C: Succeed.
C++: Error:
prog.cpp: In function ‘int main()’:
prog.cpp:20:13: error: cannot convert ‘int* (*)[2][10]’ to \
‘int* (*)[10]’ for argument ‘1’ to ‘void foo(int* (*)[10], size_t)’
foo(&a, LEN);
^
The result in C++ is what I expect, but it runs successfully in C, and it seems like it's compiler dependent because people on the chat helping ran the snippet only got a warning.
So which part I've missed? Is that C automatically did some conversion?
#include <stdio.h>
#include <stddef.h>
#define LEN 2
void foo(int* a[][10], size_t len) {
printf("%s\n", "successfully called foo.");
}
int main(void) {
// a is an LEN-array of an 10-array of (int *)
int *a[LEN][10] = {{0}};
// but the identifier `a` will decay to be a pointer of type int*[10]
// p1 is a pointer to an 10-array of (int *)
int *(*p1)[10] = 0;
foo(a, LEN);
foo(&a, LEN);
return 0;
}
Drastic edit; previous answer was wrong as pointed out in the comments.
The program is ill-formed in both C and C++. But the standards of the respective languages don't disallow successfully compiling programs that violate the imposed constraints. This allows the implementations to extend the language. Implementations are merely required to issue a diagnostic message. Both a warning and an error are conforming behaviours.
For whatever reason, the compiler that you use (through ideone) has chosen to behave differently when compiling C++.
This is not valid in C. Using gcc with -Wall -Wextra, it outputs the following:
x1.c: In function ‘main’:
x1.c:19:9: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
foo(&a, LEN);
^
x1.c:5:6: note: expected ‘int * (*)[10]’ but argument is of type ‘int * (*)[2][10]’
void foo(int* a[][10], size_t len) {
^~~
The types are not compatible. It only shows up as a warning because C tends to allow various pointer conversions even though they aren't proper.
You can however do this:
int *(*p1)[10] = a;
foo(a, LEN);
foo(p1, LEN);
I have two files as below.
ppnfs_mutex.h
...
struct ppnfs_mutex_t
{
pthread_mutex_t mutex;
pthread_t owner;
const char* context;
};
...
ppnfs_mutex.cc
#define PPNFS_MUTEX_INITIALIZER \
{ .mutex = PTHREAD_MUTEX_INITIALIZER, .owner = 0, .context = NULL, }
struct ppnfs_mutex_t ppnfs_metadata_mutex = PPNFS_MUTEX_INITIALIZER; // line 6
I use g++ to compile this file and there is an error message as:
ppnfs_mutex.cc:6:47: error: expected primary-expression before ‘.’ token
What is the problem with the code?
That style of initialisation is allowed in C, but not in C++.
In C++, either initialise without naming the fields, and hope that nobody reorders them:
#define PPNFS_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, 0, NULL}
or provide a constructor or factory function, or (if you're using C++11) use the standard thread library rather than posix threads.
I would like to create a thread passing a vector as parameter.
but i got the following errors:
error: invalid conversion from ‘int’ to ‘void* (*)(void*)’ [-fpermissive]
error: initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’ [-fpermissive]
I have the following code:
#include <iostream>
#include <vector>
#include <pthread.h>
using namespace std;
void* func(void* args)
{
vector<int>* v = static_cast<vector<int>*>(args);
cout << "Vector size: " << v->size();
}
int main ( int argc, char* argv[] )
{
vector<int> integers;
pthread_t thread;
for ( int i = 0; i < 10; i++)
integers.push_back(i+1);
// overheat call
//pthread_create( &thread, NULL, func, static_cast<void*>(&integers));
pthread_create( &thread, NULL,func,&integers);
cout << "Main thread finalized" << endl;
return 0;
}
How I can do it properly ?
Thanks
EDIT: forgot the includes posting here only; Revised.
I got new errors:
error: stray ‘\305’ in program
error: stray ‘\231’ in program
I am trying to know about it.
Thanks in advance.
FINAL EDIT : Thanks to all. Sorry, I had another int var called func in other location.
Thanks for your help.
You have forgotten to include <vector>; this confuses the compiler as it first fails to generate func, and then fails to identify it as a function in the call to pthread_create.
Once you include that, your code should compile (and you can remove the static_cast<void*> if you like); but to work correctly you also need to call pthread_join before the vector goes out of scope, and return a value from func.
UPDATE: your latest edit has broken the code: you should not cast func to void*, but leave it as a function pointer. This should work:
pthread_create(&thread, NULL, func, &integers);
Errors like stray ‘\305’ in program imply that you have some strange characters in your code, although they're not in the code you've posted. Have a look at the lines that the error messages refer to.