Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
sarehu
Apr 20, 2007

(call/cc call/cc)
This distinction is easy. An output parameter is one that you overwrite completely.

Adbot
ADBOT LOVES YOU

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...

sarehu posted:

This distinction is easy. An output parameter is one that you overwrite completely.

So, not a container that you append to, then.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Hubis posted:

So, not a container that you append to, then.

No, just like passing in a writable file descriptor doesn't make it an output parameter, nor would an object reference on which you call a method with side effects.

nielsm
Jun 1, 2009



The value of an output parameter may be undefined at function entry, the value of the output parameter will typically have changed at function exit, and the operation of the function will still be well-defined (assuming nothing else occurs in the function can cause UB.)

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...

Subjunctive posted:

No, just like passing in a writable file descriptor doesn't make it an output parameter, nor would an object reference on which you call a method with side effects.

I guess my point is that I don't think that delineating between "output parameters" and "parameters wot could have side effects" seems particularly useful from a readability perspective:
- If you have code that takes a pointer to an object that isn't an output parameter then you're going to have address decorators in the call anyways
- If you have code where you have a pointer to the object you want to use as the output for some reason then you would be lacking the decorator you're claiming helps to make the code more readable.
- The meaning of what is an "output" parameter seems kind of arbitrary to me. Why do you need to know what's an input and what's an output, and how is that different from something which is simply modified rather than "completely overwritten"?

Really it sounds like the advice is really more just "don't use non-const references, so you know anything you pass a pointer to COULD be getting changed" but to me that just becomes "be really aggressive about marking things as const".

I mean, this is all borderline stuff -- I can't imagine a codebase where readability is going to be made or broken one way or another by this. It's easy to sound judgmental about religion and programming languages. I just keep asking about it because hearing how other people thing about programming and language artifacts like that is really interesting and useful for me. For example, is there any reason why you couldn't extend the code Plorkyeran posted to have a different type for pointer parameters the function would maintain references to? Is there any advantage to using a const reference versus a const pointer? etc.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
An output parameter is something that would be a return value if the language had a good way to return multiple values. It's really not very complicated or abitrary at all.

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...

Plorkyeran posted:

An output parameter is something that would be a return value if the language had a good way to return multiple values. It's really not very complicated or abitrary at all.

.. by reference. Because you can completely return a structure without problem right now, but that's not always desirable because of size limits.

So you're saying an output parameter should have the same properties as an r-value: undefined before the function, and guaranteed to be defined after the function runs (really it's the rvalue and lvalue at the same time).

I guess I just don't understand the usefulness of trying to make this very obvious in the code, regardless of whether assuming that the address-of operator is a useful way of conveying it. Static analysis, i.e. "it's ok that this hasn't been initialized before being passed into this function"? It seems like "is a pointer" isn't really sufficient for that.

sarehu
Apr 20, 2007

(call/cc call/cc)
It's not as useful as the const/non-const delineation but it's still useful. You know, just looking at the callsite, some information about whether a variable's previous state is going to survive.

quote:

.. by reference. Because you can completely return a structure without problem right now, but that's not always desirable because of size limits.

No the problem is that there's no convenient way in the code to unpack the multiple return values in C++.

sarehu fucked around with this message at 00:01 on Dec 4, 2015

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
I don't find defining throwaway structs and accessing their members to be at all onerous :shrug:

Given that typing is certainly not the hard part of programming, a few extra characters compared to some ideal pattern-matching world is not a very high price to pay for unambiguous readability.

Phayray
Feb 16, 2004
Do ranged-based for loops iterate once, even when the container is empty? I've resolved it by other means, but I have an object with a vector member full of pointers that may or may not be empty when this object's destructor is called. I was doing this:
code:
Foo::~Foo() {
  for (auto t : things) {
    delete t;
  }
}
It was segfaulting when ~Foo() was called because t.size() was 0, so it was trying to delete...something?

Edit: Looking at it, I guess it makes sense that this fails because if it's empty, vector::begin() returns an iterator and "the returned iterator value shall not be dereferenced."

Phayray fucked around with this message at 08:17 on Dec 4, 2015

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
No, that does not make any sense. The loop will never dereference any iterators if the collection is empty. Unless these are hand-written (buggy) iterators, your bug is somewhere else; perhaps the object has already been destroyed?

Reasoning abstractly about your code is good, but sometimes you just need to look at it in a debugger.

Sex Bumbo
Aug 14, 2004
No, although the returned iterator shouldn't be dereferenced if the container is empty, the iterator will be equal to the end iterator and the loop will ever execute its body. Something else is up.

E: :(

Phayray
Feb 16, 2004
Derp, of course you guys are right, I was deleting them somewhere else but not clearing the vector. Saw it as soon as I looked at it this morning, I guess I just needed some sleep!

Phayray fucked around with this message at 15:37 on Dec 4, 2015

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
Why would I suddenly be getting a linker error telling me that the OpenGL libraries weren't found? The only thing I changed is that in stead of using dynamic libraries for assimp, I now compile it with my project and link it statically. The assimp library file links up just fine, the linker error is on my main executable. This only happens on Linux (gcc 4.8.2) while it compiles fine on Windows (MinGW 5.0.2). This is the output from ld:

code:
/usr/bin/ld: cannot find -lGL
/usr/bin/ld: cannot find -lGL
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libX11.a(xim_trans.o): In function `_XimXTransSocketUNIXConnect':
(.text+0xaff): warning: Using 'getaddrinfo' in statically linked applications requires at
[continued from last line]]runtime the shared libraries from the glibc version used for linking
collect2: error: ld returned 1 exit status
I assume the last part isn't what is causing it to exit, since it's a warning, not an error. This is the part of my cmake file I changed:

code:
#Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -std=c++11 -static-libgcc -static-libstdc++
       -static -pthread -D M_PI_2=1.57079632679 -D M_PI=3.14159265359")

[...]

#AssImp
include_directories(${LIB_DIR}/assimp/include)
add_subdirectory(${LIB_DIR}/assimp/)
target_link_libraries(BscProject assimp)
I link OpenGL by searching for the package (using -lGL in stead made no difference.) Maybe something changed with my video driver or something, but I can run OpenGL applications just fine; ld just seems to not recognise the library?

pseudorandom name
May 6, 2007

There isn't a static version of libGL

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

pseudorandom name posted:

There isn't a static version of libGL

Can the -static flag I put there for -pthread affect this line?

code:
#OpenGL
find_package(OpenGL REQUIRED)
target_link_libraries(BscProject ${OPENGL_LIBRARIES})
If not, I'm pretty sure I'm not trying to link OpenGL statically. I also tried putting -lGL before the static flag (and commenting out the above line,) with the same results. How would I even get around this? I need pthread to link statically, but I obviously don't wanna try to link OpenGL statically.

Joda fucked around with this message at 10:59 on Dec 5, 2015

pseudorandom name
May 6, 2007

-static is all or nothing.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
There might be a way to use incremental linking to just statically link specific libraries, but it will break any dynamic libraries you use that depend on those libraries, which for pthreads probably includes libGL.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Phayray posted:

Derp, of course you guys are right, I was deleting them somewhere else but not clearing the vector. Saw it as soon as I looked at it this morning, I guess I just needed some sleep!
AddressSanitizer would have made this immediately obvious. Try it next time!

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
I did some testing and you're right; removing -static from the list of flags fixes the issue. However, I'm still linking four other libraries (on top of glibc and libsdc++) statically; only I'm doing it by compiling them alongside the project, as opposed to linking them with a compiler flag. How are these two fundamentally different? I'm still just compiling a library file, then linking it against my main executable at the end.

E: Not to mention the fact that it actually works as intended on MinGW with the -static flag?

Joda fucked around with this message at 21:31 on Dec 5, 2015

Raenir Salazar
Nov 5, 2010

College Slice
Anyone here familiar with openCL?

I have a program here that takes in two arrays, one of size=10 ArrayA and another of size=100 ArrayB. I have a 2D Kernel that does 10*10 operations to fill ArrayB with values where each element is equal to the unique global id of the current work item/kernel.

The problem is that when I copy ArrayB back, I only have valid values for the first ArrayA-sized elements, the rest are garbage.

I know the kernels are running for 100 elements because I have a count incrementer and it equals 100 when it finishes, so 100 kernels had to have operated.

SimpleArray:

code:
bool bPhysics::OpenCLArrayTest()
{
	cl_context context = NULL;				// OpenCL Context
	cl_command_queue command_queue = NULL;	// OpenCL Command Queue
	cl_mem memobj_a = NULL;
	cl_mem memobj_a_size = NULL;
	cl_mem memobj_b = NULL;
	cl_mem memobj_b_size = NULL;
	cl_program program = NULL;
	cl_kernel kernel = NULL;
	cl_device_id *cdDevices = NULL;     // OpenCL device list
	cl_platform_id platform_id = NULL;		// OpenCL Platform
	cl_uint ret_num_devices;
	cl_uint ret_num_platforms;
	cl_int ret;
	cl_uint uiNumComputeUnits;
	cl_uint uiTargetDevice = 0;	        // OpenCL Device to compute on

	FILE *fp;
	char *fileName;
	char *source_str;
	size_t source_size;

	int _size = 10;
	int d_b_max_size = _size * _size;

	// d_a = device_array
	int *d_a = (int*)malloc(_size * sizeof(int));
	// d_a_size = device_array, the number of elements we pass in.
	int d_a_size = _size;

	// init values for d_a
	for (int i = 0; i < _size; i++)
	{
		d_a[i] = i;
	}

	int *d_b = (int*)malloc(d_b_max_size * sizeof(int));
	int *d_b_size = (int*)malloc(sizeof(int));

	// init values for d_b
	for (int i = 0; i < _size; i++)
	{
		d_b[i] = -1;
	}
	d_b_size[0] = 0;

	/* Get Platform and Device Info */
	ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
	if (ret < 0)
		return false;

	ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 0, NULL, &ret_num_devices);
	//ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices);
	if (ret < 0)
		return false;

	std::cout << " # of devices = " << ret_num_devices << std::endl;
	cdDevices = (cl_device_id*)malloc(ret_num_devices * sizeof(cl_device_id));
	ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, ret_num_devices, cdDevices, NULL);
	if (ret < 0)
		return false;
	uiTargetDevice = glm::clamp((int)uiTargetDevice, (int)0, (int)(ret_num_devices - 1));

	std::cout << "Using device #: " << uiTargetDevice << std::endl;
	clGetDeviceInfo(cdDevices[uiTargetDevice], CL_DEVICE_MAX_COMPUTE_UNITS, 
sizeof(uiNumComputeUnits), &uiNumComputeUnits, NULL);
	std::cout << " # of Compute Units = " << uiNumComputeUnits << std::endl;


	/* Create OpenCL context */
	context = clCreateContext(NULL, 1, &cdDevices[uiTargetDevice], NULL, NULL, &ret);
	if (ret < 0)
		return false;

	/* Create Command Queue */
	command_queue = clCreateCommandQueue(context, cdDevices[uiTargetDevice], 0, &ret);
	if (ret < 0)
		return false;

	char string[MEM_SIZE];
	fileName = "broadphase.cl";
	/* Load the source code containing the kernel*/
	fopen_s(&fp, fileName, "r");
	if (!fp) {
		fprintf(stderr, "Failed to load kernel.\n");
		exit(1);
	}
	source_str = (char*)malloc(MAX_SOURCE_SIZE);
	source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
	fclose(fp);


	/* Create Kernel Program from the source */
	program = clCreateProgramWithSource(context, 1, (const char **)&source_str,
		(const size_t *)&source_size, &ret);

	if (ret < 0)
		return false;

	/* Build Kernel Program */
	ret = clBuildProgram(program, 1, &cdDevices[uiTargetDevice], NULL, NULL, NULL);
	// First call to know the proper size
	// build failed
	if (ret != CL_SUCCESS) {

		// check build error and build status first
		clGetProgramBuildInfo(program, cdDevices[uiTargetDevice], CL_PROGRAM_BUILD_STATUS,
			sizeof(cl_build_status), &status, NULL);

		// check build log
		clGetProgramBuildInfo(program, cdDevices[uiTargetDevice],
			CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
		programLog = (char*)calloc(logSize + 1, sizeof(char));
		clGetProgramBuildInfo(program, cdDevices[uiTargetDevice],
			CL_PROGRAM_BUILD_LOG, logSize + 1, programLog, NULL);
		printf("Build failed; error=%d, status=%d, programLog:nn%s",
			ret, status, programLog);
		free(programLog);
		std::cout << "Press ENTER to continue...";
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}
	if (ret < 0)
		return false;


	/* Create OpenCL Kernel */
	kernel = clCreateKernel(program, "test_kernel", &ret);
	if (ret < 0)
		return false;

	/* Create Memory Buffer */
	memobj_a = clCreateBuffer(context, CL_MEM_READ_WRITE, _size * sizeof(int), NULL, &ret);
	if (ret < 0)
		return false;

	memobj_b = clCreateBuffer(context, CL_MEM_READ_WRITE, d_b_max_size * sizeof(int), NULL, &ret);
	if (ret < 0)
		return false;

	memobj_b_size = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int), NULL, &ret);
	if (ret < 0)
		return false;
	memobj_a_size = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int), NULL, &ret);
	if (ret < 0)
		return false;

	/* Copy input data to the memory buffer */
	ret = clEnqueueWriteBuffer(
command_queue, 
memobj_a, 
CL_TRUE, 0, _size * sizeof(int), d_a, 0, NULL, NULL);
	if (ret < 0)
		return false;
	ret = clEnqueueWriteBuffer(command_queue, memobj_b, 
CL_TRUE, 0, d_b_max_size * sizeof(int), d_b, 0, NULL, NULL);
	if (ret < 0)
		return false;
	ret = clEnqueueWriteBuffer(command_queue, memobj_a_size, 
CL_TRUE, 0, sizeof(int), &d_a_size, 0, NULL, NULL);
	if (ret < 0)
		return false;
	ret = clEnqueueWriteBuffer(command_queue, memobj_b_size, 
CL_TRUE, 0, sizeof(int), d_b_size, 0, NULL, NULL);
	if (ret < 0)
		return false;

	/* Set OpenCL Kernel Parameters */
	ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobj_a);
	if (ret < 0)
		return false;

	ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&memobj_b);
	if (ret < 0)
		return false;
	ret = clSetKernelArg(kernel, 2, sizeof(int), &memobj_a_size);
	if (ret < 0)
		return false;
	ret = clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&memobj_b_size);
	if (ret < 0)
		return false;

	/* Execute OpenCL Kernel */
	const size_t dimSize = 2;
	size_t global_item_size[dimSize];
	global_item_size[0] = _size;
	global_item_size[1] = _size;
	//size_t local_item_size = sizeWidgets;

	/* Execute OpenCL kernel as data parallel */
	ret = clEnqueueNDRangeKernel(command_queue, kernel, dimSize, NULL, 
global_item_size, NULL, 0, NULL, NULL);
	if (ret < 0)
		return false;

	/* Copy results from the memory buffer */
	/* Transfer result to host */
	ret = clEnqueueReadBuffer(command_queue, memobj_a, CL_TRUE, 0,
 _size * sizeof(int), d_a, 0, NULL, NULL);
	ret = clEnqueueReadBuffer(command_queue, memobj_b, CL_TRUE, 0, 
d_b_max_size * sizeof(int), d_b, 0, NULL, NULL);
	ret = clEnqueueReadBuffer(command_queue, memobj_b_size, CL_TRUE, 0, 
sizeof(int), d_b_size, 0, NULL, NULL);
	if (ret < 0)
		return false;

	ret = clFinish(command_queue);
	if (ret < 0)
		return false;
	/* Display Result */

	std::cout << d_b_size[0] << std::endl;
	for (int i = 0; i < d_b_max_size; i++)
	{
		std::cout << d_b[i] << std::endl;

	}

	std::cout << "Press ENTER to continue...";
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Kernel code
code:
__kernel void test_kernel(__global int *device_a_array, __global int *device_b_array, 
int _aSize, __global int *_bFinalSize)
{
	int i = get_global_id(0);
	int j = get_global_id(1);

	// map a 2D array index to a 1D array
	int index = (_aSize * j) + i;

	// pass the computer index value to device_b_array at position index
	device_b_array[index] = index;

	// increment "final size" to get count of all kernels that did work
	atom_inc(&_bFinalSize[0]);
}
I feel that the kernel isn't wrong, the number of elements I get back is dependent apparently on what global_work_group_size is, if I increase that then I get back more elements, this isn't making any sense to me.

e: So this example for inexplicible reasons works when:

ret = clSetKernelArg(kernel, 2, sizeof(int), &memobj_a_size);

is changed to:

ret = clSetKernelArg(kernel, 2, sizeof(int), &_size);

This is just strange to me.

Raenir Salazar fucked around with this message at 21:45 on Dec 5, 2015

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
According to the docs for clSetKernelArg, the kind of arg_value you're supposed to pass depends on the type of the argument, which I assume it knows by just looking at the compiled kernel function. Basically:

  • T __global *: a buffer (from clCreateBuffer)
  • T __constant *: a buffer
  • T __local *: NULL
  • image*_t: an image
  • image_buffer_t: a buffer
  • sampler_t: a pointer to a sampler
  • anything else: a pointer to that fundamental type, which will be immediately memcpy'ed out of. So for something like int, you're just supposed to pass an int*.

I don't know why the documentation is written so badly; I feel like this table should be obvious on that webpage, not something you have to awkwardly infer.

Raenir Salazar
Nov 5, 2010

College Slice

rjmccall posted:

According to the docs for clSetKernelArg, the kind of arg_value you're supposed to pass depends on the type of the argument, which I assume it knows by just looking at the compiled kernel function. Basically:

  • T __global *: a buffer (from clCreateBuffer)
  • T __constant *: a buffer
  • T __local *: NULL
  • image*_t: an image
  • image_buffer_t: a buffer
  • sampler_t: a pointer to a sampler
  • anything else: a pointer to that fundamental type, which will be immediately memcpy'ed out of. So for something like int, you're just supposed to pass an int*.

I don't know why the documentation is written so badly; I feel like this table should be obvious on that webpage, not something you have to awkwardly infer.

I'm not sure, the main issue of confusion for me is that the problem really should've been with:

code:
ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&memobj_b);
but being with

code:
ret = clSetKernelArg(kernel, 2, sizeof(int), &memobj_a_size);
Just doesn't make sense to me, this is the size of the number of the data array being passed in and it's unrelated to the array I want returned/modified, so strange. It's a completely different variable unless the memory object is what openCL uses for determining the size of the work groups?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
It is literally copying the first sizeof(int) bytes out of the object header of some buffer you allocated and passing that as the int argument.

You might have other problems but it is not surprising that that is one of them.

Phayray
Feb 16, 2004

Ralith posted:

AddressSanitizer would have made this immediately obvious. Try it next time!

This is great, thanks!

feedmegin
Jul 30, 2008

Joda posted:

I did some testing and you're right; removing -static from the list of flags fixes the issue. However, I'm still linking four other libraries (on top of glibc and libsdc++) statically; only I'm doing it by compiling them alongside the project, as opposed to linking them with a compiler flag. How are these two fundamentally different? I'm still just compiling a library file, then linking it against my main executable at the end.

E: Not to mention the fact that it actually works as intended on MinGW with the -static flag?

A static library (collection of .o files that will be copied into your eventual, dynamically linked program) is different from using the -static gcc flag (try and make a program only out of static libraries, no shared libraries at all not even libc). The only reason you'd do the latter is for compiling things like basic utilities in /bin that you want to work even if you somehow mess up/delete glibc.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

feedmegin posted:

A static library (collection of .o files that will be copied into your eventual, dynamically linked program) is different from using the -static gcc flag (try and make a program only out of static libraries, no shared libraries at all not even libc). The only reason you'd do the latter is for compiling things like basic utilities in /bin that you want to work even if you somehow mess up/delete glibc.

The reason I want to link the standard libraries and pthread statically is that I want to avoid having to redistribute their dlls with my program on WIndows (on Linux I don't really care, because installing the standard libraries is a pretty fast process.) The main reason is that while the GNU standard library license clearly states that you can redistribute a statically linked binary file however you want, I can't find any clear language on whether that exemption from the GPL extends to dynamic linking and redistribution of the C and C++ standard library .dll's.

That said I guess pthread is under a permissive license, so I could just settle with linking libc and c++ statically and then redistribute with libwinpthread.dll.

Doctor w-rw-rw-
Jun 24, 2008
Two notes:
  • Microsoft Visual C++ runtime: Can't redistribute with a GPL program. The GPL has a system linking exception, so if it's included with the OS you're fine, but if you have to redistribute it with your executable, it falls under the GPL.
  • Glibc isn't even GPL. It's BSD+LGPL.

What exactly is your issue? Can you explain using actual library or file names? From the sounds of it you should be able to statically link both of those.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

Doctor w-rw-rw- posted:

Two notes:
  • Glibc isn't even GPL. It's BSD+LGPL.

Really? I'm pretty sure I read that the GNU standard libraries (C/C++) were under the GPL, but exempt in such a way that you could link them statically and redistribute your binary without restrictions. I may have misunderstood what I read though.

Doctor w-rw-rw- posted:

What exactly is your issue? Can you explain using actual library or file names? From the sounds of it you should be able to statically link both of those.

I was getting a linker error on OpenGL (ld couldn't find -lGL), because I was using the -static flag to link pthread statically. Obviously I can't link OpenGL statically, because its concrete implementation varies depending on hardware and driver versions.

Doctor w-rw-rw-
Jun 24, 2008
Ah, okay.

Joda posted:

Really? I'm pretty sure I read that the GNU standard libraries (C/C++) were under the GPL, but exempt in such a way that you could link them statically and redistribute your binary without restrictions. I may have misunderstood what I read though.
"GPL with linking exception" means the license allows the library (which it covers in both the source code and compiled binary situation) can be redistributed without contamination. This does include dynamic as well as static linking I believe.

Edison was a dick
Apr 3, 2010

direct current :roboluv: only

feedmegin posted:

The only reason you'd do the latter is for compiling things like basic utilities in /bin that you want to work even if you somehow mess up/delete glibc.

Fun fact: the s in /sbin stands for static and was for that purpose, only later was it decided that it was for administrator programs and not included in PATH by default.

The /sbin vs /usr/sbin was because they ran out of space on the drive that / was mounted at, and moved binaries that weren't needed to mount the /usr drive, which at that point was for users' files. After they filled that up with binaries they put another drive in, mounted it at /home and put users' files on there, hence the weird names for /usr and /home.

Paniolo
Oct 9, 2007

Heads will roll.
I learned something new today.

code:
struct foo { int x; };

foo f;

f.x = -1;
new (&f) foo();
What's f.x?

sarehu
Apr 20, 2007

(call/cc call/cc)
Zero? Because you wrote the ()?

Paniolo
Oct 9, 2007

Heads will roll.
Under Microsoft compilers it was -1, under Clang it was 0. My actual case was a bit more complex though, not sure how VC++ would process the more trivial example.

I definitely did not expect placement new to value-initialize.

FamDav
Mar 29, 2008

Paniolo posted:

I learned something new today.

code:
struct foo { int x; };

foo f;

f.x = -1;
new (&f) foo();
What's f.x?

This is how initialization of new expressions are handled

5.3.4.17 posted:

A new-expression that creates an object of type T initializes that object as follows:
— If the new-initializer is omitted, the object is default-initialized (8.5). [Note: If no initialization is performed, the object has an indeterminate value. — end note ]
— Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.

So "new (&f) foo" is default-initialized. "new (&f) foo()" is direct-initialized, and the specific rule for that we're interested in is

8.5.17.4 posted:

- If the initializer is (), the object is value-initialized.

which eventually gets you to zero-initialization.

FamDav
Mar 29, 2008
also i think direct-initialization for T() only became a thing in c++03, so knowing Microsoft and backwards compatibility/standards compliance they decided to keep the legacy behavior.

sarehu
Apr 20, 2007

(call/cc call/cc)
The use of () to mean zero-initialization is just the stupidest thing. I mean C++ gets a lot of dumb poo poo from C, but this is a special gift from C++.

MutantBlue
Jun 8, 2001

Paniolo posted:

Under Microsoft compilers it was -1

It's 0 with VS2015

OneEightHundred
Feb 28, 2008

Soon, we will be unstoppable!

sarehu posted:

The use of () to mean zero-initialization is just the stupidest thing. I mean C++ gets a lot of dumb poo poo from C, but this is a special gift from C++.
Unless you consider non-initialization to be dumb poo poo from C.

Adbot
ADBOT LOVES YOU

Bonfire Lit
Jul 9, 2008

If you're one of the sinners who caused this please unfriend me now.

OneEightHundred posted:

Unless you consider non-initialization to be dumb poo poo from C.
It is, but having the compiler do different initialization depending on whether or not an empty set of parentheses is present is also dumb poo poo.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply